Orchard源码分析(7.2):Controller相关

概述
默认情况下,ASP.NET MVC内置的DefaultControllerFactory负责Controller实例的创建。Orchard定义了一个继承自DefaultControllerFactory类的Orchard.Mvc.OrchardControllerFactory类并在OrchardStarter类中进行注册:
         // 以下代码来在Orchard.Environment.OrchardStarter类
          ControllerBuilder .Current.SetControllerFactory( new   OrchardControllerFactory ());
OrchardControllerFactory作用是能从Shell生命周期的Autofac"子容器"中解析(Resolver)Controller类型,再根据类型解析Controller实例。这里就引出这些问题:Controller类型在什么时候被注册到Autofac容器中,Controller的类型如何被解析出来,Controller的实例如何被解析出来。
 
一、Controller注册
在激活Shell之前,会创建Shell的上下文对象ShellContext,在这个过程中会将Shell需要用到的Controller注册到Shell作用域的Autofac容器中:
                     // 以下代码来在Orchard.Environment.ShellBuilders.ShellContainerFactory类的CreateContainer方法
                      foreach   ( var   item   in   blueprint.Controllers) {
                          var   serviceKeyName = (item.AreaName +   "/"   + item.ControllerName).ToLowerInvariant();
                          var   serviceKeyType = item.Type;
                        RegisterType(builder, item)
                            .EnableDynamicProxy(dynamicProxyContext)
                            .Keyed<   IController >(serviceKeyName)
                            .Keyed<   IController >(serviceKeyType)
                            .WithMetadata(   "ControllerType" , item.Type)
                            .InstancePerDependency()
                            .OnActivating(e =>s {
                                  // necessary to inject custom filters dynamically
                                  // see FilterResolvingActionInvoker
                                  var   controller = e.Instance   as   Controller ;
                                  if   (controller !=   null   )
                                    controller.ActionInvoker = (   IActionInvoker )e.Context.ResolveService( new   TypedService ( typeof   ( IActionInvoker )));
                            });
                    }
 
                      foreach   ( var   item   in   blueprint.HttpControllers) {
                          var   serviceKeyName = (item.AreaName +   "/"   + item.ControllerName).ToLowerInvariant();
                          var   serviceKeyType = item.Type;
                        RegisterType(builder, item)
                            .EnableDynamicProxy(dynamicProxyContext)
                            .Keyed<   IHttpController >(serviceKeyName)
                            .Keyed<   IHttpController >(serviceKeyType)
                            .WithMetadata(   "ControllerType" , item.Type)
                            .InstancePerDependency();
                    }
 
          // 以下代码来在Orchard.Environment.ShellBuilders.ShellContainerFactory类
        private   IRegistrationBuilder < object   ,   ConcreteReflectionActivatorData ,   SingleRegistrationStyle > RegisterType( ContainerBuilder   builder,   ShellBlueprintItem   item) {
              return   builder.RegisterType(item.Type)
                .WithProperty(   "Feature" , item.Feature)
                .WithMetadata(   "Feature" , item.Feature);
        }
二、ControllerFactory
既然Controller已经被注册到了Autofac容器中,则很容易提取出来:
      // 以下代码来在Orchard.Mvc.ControllerFactory类
     ///   <summary>
      ///   Overrides the default controller factory to resolve controllers using LoC, based their areas and names.
      ///   </summary>
      public   class   OrchardControllerFactory   :   DefaultControllerFactory   {
          ///   <summary>
          ///   Tries to resolve an instance for the controller associated with a given service key for the work context scope.
          ///   </summary>
          ///   <typeparam name="T">   The type of the controller. </typeparam>
          ///   <param name="workContext">   The work context. </param>
          ///   <param name="serviceKey">   The service key for the controller.   </param>
          ///   <param name="instance">   The controller instance. </param>
          ///   <returns>   True if the controller was resolved; false otherwise.   </returns>
          protected   bool   TryResolve<T>( WorkContext   workContext,   object   serviceKey,   out   T instance) {
              if   (workContext !=   null   && serviceKey !=   null ) {
                  var   key =   new   KeyedService (serviceKey,   typeof   (T));
                  object   value;
                  if   (workContext.Resolve< ILifetimeScope   >().TryResolveService(key,   out   value)) {
                    instance = (T) value;
                      return   true   ;
                }
            }
 
            instance =   default (T);
              return   false   ;
        }
 
          ///   <summary>
          ///   Returns the controller type based on the name of both the controller and area.
          ///   </summary>
          ///   <param name="requestContext">   The request context from where to fetch the route data containing the area. </param>
          ///   <param name="controllerName">   The controller name. </param>
          ///   <returns>   The controller type. </returns>
          ///   <example>   ControllerName: Item, Area: Containers would return the type for the ItemController class. </example>
          protected   override   Type   GetControllerType(   RequestContext   requestContext,   string   controllerName) {
              var   routeData = requestContext.RouteData;
 
              // Determine the area name for the request, and fall back to stock orchard controllers
              var   areaName = routeData.GetAreaName();
 
              // Service name pattern matches the identification strategy
              var   serviceKey = (areaName +   "/"   + controllerName).ToLowerInvariant();
 
              // Now that the request container is known - try to resolve the controller information
              Meta < Lazy   < IController >> info;
              var   workContext = requestContext.GetWorkContext();
              if   (TryResolve(workContext, serviceKey,   out   info)) {
                  return   ( Type   ) info.Metadata[ "ControllerType" ];
            }
 
              return   null   ;
        }
 
          ///   <summary>
          ///   Returns an instance of the controller.
          ///   </summary>
          ///   <param name="requestContext">   The request context from where to fetch the route data containing the area. </param>
          ///   <param name="controllerType">   The controller type. </param>
          ///   <returns>   An instance of the controller if it's type is registered; null if otherwise.   </returns>
          protected   override   IController   GetControllerInstance(   RequestContext   requestContext,   Type   controllerType) {
              IController   controller;
              var   workContext = requestContext.GetWorkContext();
              if   (TryResolve(workContext, controllerType,   out   controller)) {
                  return   controller;
            }
 
              // fail as appropriate for MVC's expectations
              return   base   .GetControllerInstance(requestContext, controllerType);
        }
    }
 
 
三、ActionInvoker
在成功创建Controller实例后,会将其ActionInvoker设置成Orchard.Mvc.FilterResolvingActionInvoker。
我们知道,ASP.NET MVC中,我们可以将Filter以Attribute的形式定义在Controller或Action上。Orchard提供了一个Filter Provider机制,即可以将一些Filter定义在其他地方,在使用Filter之前再提取出来。这方面比较简单,直接看FilterResolvingActionInvoker的定义:
      // 以下代码来在Orchard.Mvc.Filters.FilterResolvingActionInvoker类
     public   class   FilterResolvingActionInvoker   :   ControllerActionInvoker   {
          private   readonly   IEnumerable <   IFilterProvider > _filterProviders;
 
          public   FilterResolvingActionInvoker( IEnumerable   < IFilterProvider > filterProviders) {
            _filterProviders = filterProviders;
        }
 
          protected   override   FilterInfo   GetFilters( ControllerContext   controllerContext,   ActionDescriptor   actionDescriptor) {
              var   filters=   base   .GetFilters(controllerContext, actionDescriptor);
              foreach ( var   provider   in   _filterProviders) {
                provider.AddFilters(filters);
            }
              return   filters;
        }
    }
 
只要一个Filter实现了Orchard.Mvc.Filters.FilterProvider:FilterProvider抽象类,就能非常方便的将Filter应用到所有Action之上。另外,高级的应用可以直接实现IFilterProvider接口,不过一般实现FilterProvider抽象类就行了。
 
相关类型:
Orchard.Mvc.OrchardControllerFactory:System.Web.Mvc.DefaultActionInvoker
Orchard.Mvc.Filters.FilterResolvingActionInvoker:System.Web.Mvc.ControllerActionInvoker
Orchard.Mvc.Filters.IFilterProvider
Orchard.Environment.ShellBuilders.ShellContainerFactory
Orchard.Environment.AutofacUtil.DynamicProxy2.DynamicProxyContext
 
 
 

你可能感兴趣的:(controller)