概述
默认情况下,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

Orchard源码分析(7.2):Controller相关的更多相关文章

  1. Orchard源码分析(5):Host相关(Orchard.Environment.DefaultOrchardHost类)

    概述 Host 是应用程序域级的单例,代表了Orchard应用程序.其处理应用程序生命周期中的初始化.BeginRequest事件.EndRequest事件等. 可以简单理解为HttpApplicat ...

  2. 消息队列的一些场景及源码分析,RocketMQ使用相关问题及性能优化

    前文目录链接参考: 消息队列的一些场景及源码分析,RocketMQ使用相关问题及性能优化 https://www.cnblogs.com/yizhiamumu/p/16694126.html 消息队列 ...

  3. 《k8s 源码分析》- Custom Controller 之 Informer

    Custom Controller 之 Informer 概述 架构概览 reflector - List & Watch API Server Reflector 对象 ListAndWat ...

  4. Orchard源码分析(1):Orchard架构

      本文主要参考官方文档"How Orchard works"以及Orchardch上的翻译.   源码分析应该做到庖丁解牛,而不是以管窥豹或瞎子摸象.所以先对Orchard架构有 ...

  5. Orchard源码分析(7.1):Routing(路由)相关

    概述 关于ASP.NET MVC中路由有两个基本核心作用,一是通过Http请求中的Url参数等信息获取路由数据(RouteData),路由数据包含了area.controller.action的名称等 ...

  6. Orchard源码分析(6):Shell相关

    概述在Orchard中,提出子站点(Tenant)的概念,目的是为了增加站点密度,即一个应用程序域可以有多个子站点. Shell是子站点(Tenant)级的单例,换句话说Shell代表了子站点.对比来 ...

  7. Orchard源码分析(7):ASP.NET MVC相关

    概述 Orchard归根结底是一个ASP.NET MVC(以后都简称为MVC)应用,但在前面的分析中,与MVC相关内容的涉及得很少.MVC提供了非常多的扩展点,本文主要关注Orchard所做的扩展.主 ...

  8. Orchard源码分析(4.4):Orchard.Caching.CacheModule类

    概述 CacheModule也是一个Autofac模块.   一.CacheModule类 CacheModule将DefaultCacheManager注册为ICacheManager:       ...

  9. Orchard源码分析(5.1):Host初始化(DefaultOrchardHost.Initialize方法)

    概述 Orchard作为一个可扩展的CMS系统,是由一系列的模块(Modules)或主题(Themes)组成,这些模块或主题统称为扩展(Extensions).在初始化或运行时需要对扩展进行安装:De ...

  10. Orchard源码分析(4.3):Orchard.Events.EventsModule类(Event Bus)

    概述 采用Event Bus模式(事件总线),可以使观察者模式中的观察者和被观察者实现解耦. 在.Net 中使用观察者模式,可以使用事件(委托)和接口(类).Orchard Event  Bus使用的 ...

随机推荐

  1. 简进祥==iOS 3DES加密解密

    3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称.它相当于是对每个数据块应用三次DES加密算法.由于计 ...

  2. 71.Android之长连接实现

    转载:http://blog.csdn.net/qq_23547831/article/details/51690047 本文中我们将讲解一下App的长连接实现.一般而言长连接已经是App的标配了,推 ...

  3. 58. Android一些开发习惯总结

    作者:漫步 链接:https://www.zhihu.com/question/27227425/answer/35973793 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  4. Shiro-密码的MD5加密

    1.密码的加密 在数据表中存的密码不应该是123456,而应该是123456加密之后的字符串,而且还要求这个加密算法是不可逆的,即由加密后的字符串不能反推回来原来的密码,如果能反推回来那这个加密是没有 ...

  5. css-css权威指南学习笔记3

    第三章 结构和层叠 1.确定应向一个元素应用哪些值时,用户代理不仅要考虑继承,还要考虑声明的特殊性,另外需要考虑声明本身的来源,这个过程就称为层叠.. 2.特殊性.如果一个元素有两个或多个冲突的属性声 ...

  6. UOJ244 【UER #7】短路

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  7. CLR/.NET/C#/Visual Studio/ASP.NET各版本之间的关系(转)

    由于这篇文章记录的是2015年7月,那时.net core还是叫做.net core 5 名词定义 下列这些名词,写.NET 的人一定都不陌生,但你是否有真正理解呢?如果看了我的摘要文字说明还无法理解 ...

  8. 硬盘分区时GPT和MBR的区别/选择

    最明显的区别是MBR最大支持2T的硬盘,而GPT则更大. 1.最先出现在Windows8中设置新磁盘,系统会询问你是想要使用MBR还是GPT分区,GPT是一种新的硬盘分区标准.GPT带来了很多新特性, ...

  9. 如何自己编写一个easyui插件续

    接着如何自己编写一个easyui插件继续分享一下如何从上一节写的“hello”插件继承出一个“hello2”. 参考了combobox的源码中继承combo,当然我这个简单很多了.都是根据自己的理解来 ...

  10. 如何自己编写一个easyui插件

    本文介绍如何通过参考1.4.2版本的progressbar的源码自己编写一个HelloWorld级别的easyui插件,以及如何拓展插件的功能. 有利于我们理解easyui插件的实现,以及了解如何对e ...