あなたをオープンソースに連れて行きます-ASP.NET_MVC(八)


前編ではG e t C o r l e TypeWithinNamespacesメソッドについて述べたが,その定義に入るとControllerTypeCacheが呼び出されたことを追跡した.GetControllerTypeメソッドは、ControllerType Cacheという名前から、あるキャッシュからコントローラタイプを検索していると推測できます.これを追跡して、コードセグメント1に入ります.
   
    public ICollection<Type> GetControllerTypes(string controllerName,HashSet<string> namespaces)
        {
           HashSet<Type> matchingTypes = new HashSet<Type>();
 
           ILookup<string, Type> namespaceLookup;
           if (_cache.TryGetValue(controllerName, out namespaceLookup))
           {
               // this friendly name was located in the cache, now cycle throughnamespaces
               if (namespaces != null)
               {
                    foreach (stringrequestedNamespace in namespaces)
                    {
                        foreach (vartargetNamespaceGrouping in namespaceLookup)
                        {
                            if(IsNamespaceMatch(requestedNamespace, targetNamespaceGrouping.Key))
                            {
                               matchingTypes.UnionWith(targetNamespaceGrouping);
                            }
                        }
                    }
               }
               else
               {
                    // if the namespacesparameter is null, search *every* namespace
                    foreach (var namespaceGroup innamespaceLookup)
                    {
                       matchingTypes.UnionWith(namespaceGroup);
                    }
               }
           }
 
           return matchingTypes;
        }

コードセグメント1
コードセグメント1では、文[_cache.TryGetValue(controllerName,out namespaceLookup)]を参照してください.Cacheは辞書オブジェクトであり、その操作についてはコードセグメント2を参照してください.
   
    public void EnsureInitialized(IBuildManager buildManager)
        {
           if (_cache == null)
           {
               lock (_lockObj)
                {
                    if (_cache == null)
                    {
                        List<Type>controllerTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(TypeCacheName,IsControllerType, buildManager);
                        var groupedByName =controllerTypes.GroupBy(
                            t =>t.Name.Substring(0, t.Name.Length - "Controller".Length),
                           StringComparer.OrdinalIgnoreCase);
                        _cache =groupedByName.ToDictionary(
                            g => g.Key,
                            g =>g.ToLookup(t => t.Namespace ?? String.Empty,StringComparer.OrdinalIgnoreCase),
                           StringComparer.OrdinalIgnoreCase);
                    }
               }
            }
        }

コードセグメント2
コードセグメント2でGetFilteredTypesFromAssembliesメソッドを見つけ、その定義(コードセグメント3)に追跡します.中には、「//first,try reading from the cache on disk」、「//if reading from the cache failed,enumerate over every assemblylooking for a matching type」、「//finally,save thecache back to disk」の3つの目立つ注釈があります.マイクロソフトのオープンソースプロジェクトチームは「三」という数字が好きそうです.ほほほ!まず、ディスクキャッシュを読み込んでみます.キャッシュの読み取りに失敗した場合、すべてのプログラムセットを列挙して、一致するタイプを探します.最後に、キャッシュをディスクに保存します.これにより、MVCフレームワークがキャッシュからコントローラタイプを取得したという推測が検証される.
       public static List<Type> GetFilteredTypesFromAssemblies(stringcacheName, Predicate<Type> predicate, IBuildManager buildManager)
        {
           TypeCacheSerializer serializer = new TypeCacheSerializer();
 
           // first, try reading from the cache on disk
           List<Type> matchingTypes = ReadTypesFromCache(cacheName,predicate, buildManager, serializer);
           if (matchingTypes != null)
           {
               return matchingTypes;
           }
 
           // if reading from the cache failed, enumerate over every assemblylooking for a matching type
           matchingTypes = FilterTypesInAssemblies(buildManager,predicate).ToList();
 
           // finally, save the cache back to disk
           SaveTypesToCache(cacheName, matchingTypes, buildManager, serializer);
 
           return matchingTypes;
        }

コードセグメント3
では、コントローラのタイプを入手しました.DefaultControllerFactoryのCreateControllerメソッドに戻り、「IController controller=GetControllerInstance(requestContext,controller Type);」という文を見つけます.この文の役割はIControllerインタフェースをインスタンス化することです.GetControllerInstanceの定義をトレースします.コードセグメント4を参照してください.
     
  protected internal virtual IControllerGetControllerInstance(RequestContext requestContext, Type controllerType)
        {
           if (controllerType == null)
           {
               throw new HttpException(404,
                                       String.Format(
                                           CultureInfo.CurrentCulture,
                                           MvcResources.DefaultControllerFactory_NoControllerFound,
                                           requestContext.HttpContext.Request.Path));
           }
           if (!typeof(IController).IsAssignableFrom(controllerType))
           {
               throw new ArgumentException(
                    String.Format(
                       CultureInfo.CurrentCulture,
                       MvcResources.DefaultControllerFactory_TypeDoesNotSubclassControllerBase,
                        controllerType),
                   "controllerType");
           }
           return ControllerActivator.Create(requestContext, controllerType);
        }

コードセグメント4
コードセグメント4の最後の文【return ControllerActivatvator.Create(requestContext,controllerType);】この文がIControllerインスタンスを作成しました.
OK、コントローラのインスタンス化が完了しました.
次に、ControllerまたはActionを実行する前にフィルタ処理を行う「フィルタ」、すなわちFilterについて説明します.その原理を見てみましょう.コードセグメント5を参照してください.これはControllerActionInvokerクラスの1つの方法であり、もちろん、ControllerActionInvokerはIActionInvokerインタフェースを実現している.
public virtual boolInvokeAction(ControllerContext controllerContext, string actionName)
        {
           if (controllerContext == null)
           {
               throw new ArgumentNullException("controllerContext");
           }
 
           Contract.Assert(controllerContext.RouteData != null);
           if (String.IsNullOrEmpty(actionName) &&!controllerContext.RouteData.HasDirectRouteMatch())
           {
               throw new ArgumentException(MvcResources.Common_NullOrEmpty,"actionName");
           }
 
           ControllerDescriptor controllerDescriptor =GetControllerDescriptor(controllerContext);
           ActionDescriptor actionDescriptor = FindAction(controllerContext,controllerDescriptor, actionName);
 
            if (actionDescriptor != null)
           {
               FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
 
               try
               {
                    AuthenticationContextauthenticationContext = InvokeAuthenticationFilters(controllerContext,filterInfo.AuthenticationFilters, actionDescriptor);
 
                    if(authenticationContext.Result != null)
                    {
                        // An authenticationfilter signaled that we should short-circuit the request. Let all
                        // authenticationfilters contribute to an action result (to combine authentication
                        // challenges). Then,run this action result.
                       AuthenticationChallengeContext challengeContext =InvokeAuthenticationFiltersChallenge(
                            controllerContext,filterInfo.AuthenticationFilters, actionDescriptor,
                           authenticationContext.Result);
                        InvokeActionResult(controllerContext,challengeContext.Result ?? authenticationContext.Result);
                    }
                    else
                    {
                        AuthorizationContextauthorizationContext = InvokeAuthorizationFilters(controllerContext,filterInfo.AuthorizationFilters, actionDescriptor);
                        if(authorizationContext.Result != null)
                        {
                            // An authorizationfilter signaled that we should short-circuit the request. Let all
                            // authenticationfilters contribute to an action result (to combine authentication
                            // challenges).Then, run this action result.
                           AuthenticationChallengeContext challengeContext =InvokeAuthenticationFiltersChallenge(
                               controllerContext, filterInfo.AuthenticationFilters, actionDescriptor,
                               authorizationContext.Result);
                            InvokeActionResult(controllerContext,challengeContext.Result ?? authorizationContext.Result);
                        }
                        else
                        {
                            if(controllerContext.Controller.ValidateRequest)
                            {
                               ValidateRequest(controllerContext);
                            }
 
                           IDictionary<string, object> parameters =GetParameterValues(controllerContext, actionDescriptor);
                            ActionExecutedContextpostActionContext = InvokeActionMethodWithFilters(controllerContext,filterInfo.ActionFilters, actionDescriptor, parameters);
 
                            // The actionsucceeded. Let all authentication filters contribute to an action result (to
                            // combineauthentication challenges; some authentication filters need to do negotiation
                            // even on asuccessful result). Then, run this action result.
                           AuthenticationChallengeContextchallengeContext = InvokeAuthenticationFiltersChallenge(
                               controllerContext, filterInfo.AuthenticationFilters, actionDescriptor,
                               postActionContext.Result);
                           InvokeActionResultWithFilters(controllerContext,filterInfo.ResultFilters,
                               challengeContext.Result ?? postActionContext.Result);
                        }
                    }
               }
               catch (ThreadAbortException)
               {
                    // This type of exceptionoccurs as a result of Response.Redirect(), but we special-case so that
                    // the filters don't seethis as an error.
                    throw;
               }
               catch (Exception ex)
               {
                    // something blew up, soexecute the exception filters
                    ExceptionContextexceptionContext = InvokeExceptionFilters(controllerContext,filterInfo.ExceptionFilters, ex);
                    if(!exceptionContext.ExceptionHandled)
                    {
                        throw;
                    }
                   InvokeActionResult(controllerContext, exceptionContext.Result);
               }
 
               return true;
           }
 
           // notify controller that no method matched
           return false;
        }

コードセグメント5
コードセグメント5からは、まずGetFilters法によってすべてのFilterが得られる.次に、AuthenticationFiltersが存在するかどうかをチェックし、存在する場合は実行し、そうでない場合はAuthorizationFiltersが存在するかどうかをチェックし、存在する場合は実行し、そうでない場合はActionおよびActionResultを実行します.つまり、コントローラは、Actionを実行する前に、まずAuthenticationとAuthorizationの2つのフィルタをチェックし、存在する場合に実行します.
続きを待つ....