zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    1 Quartz开始
    1 WCF 一个基础理论 以及如何实现一个简单wcf服务
    计时器timer的使用
    获取当前电脑的cpu使用率、内存使用率
    在asp.net core中使用cookie认证
    在.net core项目中想使用类似iis上面虚拟目录的功能
    有这样一个URL:http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e,请写一段JS程序提取URL中的各个GET参数(参数名和参数个数不确定),将其按key-value形式返回到一个json结构中,如{a:’1′, b:’2′, c:”, d:’xxx’, e:undefined}。
    输出今天的日期,以YYYY-MM-DD的方式,比如今天是2014年9月26日,则输出2014-09-26
    window.onload 和document ready的区别
    call和apply的区别
  • 原文地址:https://www.cnblogs.com/lhxsoft/p/5322626.html
Copyright © 2011-2022 走看看