惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
爱范儿
爱范儿
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
罗磊的独立博客
M
MIT News - Artificial intelligence
D
Docker
量子位
T
Tailwind CSS Blog
人人都是产品经理
人人都是产品经理
月光博客
月光博客
有赞技术团队
有赞技术团队
J
Java Code Geeks
A
About on SuperTechFans
P
Proofpoint News Feed
Jina AI
Jina AI
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
Microsoft Security Blog
Microsoft Security Blog
V
V2EX
GbyAI
GbyAI
F
Fortinet All Blogs

博客园 - alby

在 ASP.NET Core Web API 中处理 Patch 请求 一种有界队列(Bounded Buffer)的实现 基于 Mediasoup 的 Abp vNext 视频会议模块 使用 ASP.NET Core 作为 mediasoup 的信令服务器 ASP.NET Core 的 `Core` 有几种写法? ASP.NET Core MVC 授权的扩展:自定义 Authorize Attribute 和 IApplicationModelProvide OrchardCore 如何实现模块化( Modular )和 Multi-Tenancy [iOS]关于状态栏(UIStatusBar)的若干问题 [iOS]关于视频方向的若干问题 --2015-06-24-- Orchard源码分析(7.1):Routing(路由)相关 Orchard源码分析(7):ASP.NET MVC相关 Orchard源码分析(4.4):Orchard.Caching.CacheModule类 Orchard源码分析(6):Shell相关 Orchard源码分析(5.3):EndRequest事件处理(DefaultOrchardHost.EndRequest方法) Orchard源码分析(5.2):BeginRequest事件处理(DefaultOrchardHost.BeginRequest方法) Orchard源码分析(5.1):Host初始化(DefaultOrchardHost.Initialize方法) Orchard源码分析(5):Host相关(Orchard.Environment.DefaultOrchardHost类) Orchard源码分析(4.3):Orchard.Events.EventsModule类(Event Bus)
Orchard源码分析(7.2):Controller相关
alby · 2013-10-11 · via 博客园 - alby

概述

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