您的位置:首页 > 其它

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

2013-10-11 16:40 375 查看
概述
默认情况下,ASP.NET MVC内置的DefaultControllerFactory负责Controller实例的创建。Orchard定义了一个继承自DefaultControllerFactory类的Orchard.Mvc.OrchardControllerFactory类并在OrchardStarter类中进行注册:
[align=left] // 以下代码来在Orchard.Environment.OrchardStarter类[/align]
[align=left] ControllerBuilder.Current.SetControllerFactory(new OrchardControllerFactory());[/align]
OrchardControllerFactory作用是能从Shell生命周期的Autofac"子容器"中解析(Resolver)Controller类型,再根据类型解析Controller实例。这里就引出这些问题:Controller类型在什么时候被注册到Autofac容器中,Controller的类型如何被解析出来,Controller的实例如何被解析出来。

一、Controller注册
在激活Shell之前,会创建Shell的上下文对象ShellContext,在这个过程中会将Shell需要用到的Controller注册到Shell作用域的Autofac容器中:

[align=left] // 以下代码来在Orchard.Environment.ShellBuilders.ShellContainerFactory类的CreateContainer方法[/align]
[align=left] foreach (var item in blueprint.Controllers) {[/align]
[align=left] var serviceKeyName = (item.AreaName + "/" + item.ControllerName).ToLowerInvariant();[/align]
[align=left] var serviceKeyType = item.Type;[/align]
[align=left] RegisterType(builder, item)[/align]
[align=left] .EnableDynamicProxy(dynamicProxyContext)[/align]
[align=left] .Keyed< IController>(serviceKeyName)[/align]
[align=left] .Keyed< IController>(serviceKeyType)[/align]
[align=left] .WithMetadata( "ControllerType", item.Type)[/align]
[align=left] .InstancePerDependency()[/align]
[align=left] .OnActivating(e =>s {[/align]
[align=left] // necessary to inject custom filters dynamically[/align]
[align=left] // see FilterResolvingActionInvoker[/align]
[align=left] var controller = e.Instance as Controller;[/align]
[align=left] if (controller != null )[/align]
[align=left] controller.ActionInvoker = ( IActionInvoker)e.Context.ResolveService(new TypedService(typeof (IActionInvoker)));[/align]
[align=left] });[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] foreach (var item in blueprint.HttpControllers) {[/align]
[align=left] var serviceKeyName = (item.AreaName + "/" + item.ControllerName).ToLowerInvariant();[/align]
[align=left] var serviceKeyType = item.Type;[/align]
[align=left] RegisterType(builder, item)[/align]
[align=left] .EnableDynamicProxy(dynamicProxyContext)[/align]
[align=left] .Keyed< IHttpController>(serviceKeyName)[/align]
[align=left] .Keyed< IHttpController>(serviceKeyType)[/align]
[align=left] .WithMetadata( "ControllerType", item.Type)[/align]
[align=left] .InstancePerDependency();[/align]
[align=left] }[/align]

[align=left] [/align]
[align=left] // 以下代码来在Orchard.Environment.ShellBuilders.ShellContainerFactory类[/align]
[align=left] private IRegistrationBuilder<object , ConcreteReflectionActivatorData, SingleRegistrationStyle> RegisterType(ContainerBuilder builder, ShellBlueprintItem item) {[/align]
[align=left] return builder.RegisterType(item.Type)[/align]
[align=left] .WithProperty( "Feature", item.Feature)[/align]
[align=left] .WithMetadata( "Feature", item.Feature);[/align]
[align=left] }[/align]

二、ControllerFactory
既然Controller已经被注册到了Autofac容器中,则很容易提取出来:
[align=left] // 以下代码来在Orchard.Mvc.ControllerFactory类[/align]
[align=left] /// <summary>[/align]
[align=left] /// Overrides the default controller factory to resolve controllers using LoC, based their areas and names.[/align]
[align=left] /// </summary>[/align]
[align=left] public class OrchardControllerFactory : DefaultControllerFactory {[/align]
[align=left] /// <summary>[/align]
[align=left] /// Tries to resolve an instance for the controller associated with a given service key for the work context scope.[/align]
[align=left] /// </summary>[/align]
[align=left] /// <typeparam name="T"> The type of the controller.</typeparam>[/align]
[align=left] /// <param name="workContext"> The work context.</param>[/align]
[align=left] /// <param name="serviceKey"> The service key for the controller. </param>[/align]
[align=left] /// <param name="instance"> The controller instance.</param>[/align]
[align=left] /// <returns> True if the controller was resolved; false otherwise. </returns>[/align]
[align=left] protected bool TryResolve<T>(WorkContext workContext, object serviceKey, out T instance) {[/align]
[align=left] if (workContext != null && serviceKey != null) {[/align]
[align=left] var key = new KeyedService(serviceKey, typeof (T));[/align]
[align=left] object value;[/align]
[align=left] if (workContext.Resolve<ILifetimeScope >().TryResolveService(key, out value)) {[/align]
[align=left] instance = (T) value;[/align]
[align=left] return true ;[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] instance = default(T);[/align]
[align=left] return false ;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] /// <summary>[/align]
[align=left] /// Returns the controller type based on the name of both the controller and area.[/align]
[align=left] /// </summary>[/align]
[align=left] /// <param name="requestContext"> The request context from where to fetch the route data containing the area.</param>[/align]
[align=left] /// <param name="controllerName"> The controller name.</param>[/align]
[align=left] /// <returns> The controller type.</returns>[/align]
[align=left] /// <example> ControllerName: Item, Area: Containers would return the type for the ItemController class.</example>[/align]
[align=left] protected override Type GetControllerType( RequestContext requestContext, string controllerName) {[/align]
[align=left] var routeData = requestContext.RouteData;[/align]
[align=left] [/align]
[align=left] // Determine the area name for the request, and fall back to stock orchard controllers[/align]
[align=left] var areaName = routeData.GetAreaName();[/align]
[align=left] [/align]
[align=left] // Service name pattern matches the identification strategy[/align]
[align=left] var serviceKey = (areaName + "/" + controllerName).ToLowerInvariant();[/align]
[align=left] [/align]
[align=left] // Now that the request container is known - try to resolve the controller information[/align]
[align=left] Meta<Lazy <IController>> info;[/align]
[align=left] var workContext = requestContext.GetWorkContext();[/align]
[align=left] if (TryResolve(workContext, serviceKey, out info)) {[/align]
[align=left] return (Type ) info.Metadata["ControllerType"];[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] return null ;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] /// <summary>[/align]
[align=left] /// Returns an instance of the controller.[/align]
[align=left] /// </summary>[/align]
[align=left] /// <param name="requestContext"> The request context from where to fetch the route data containing the area.</param>[/align]
[align=left] /// <param name="controllerType"> The controller type.</param>[/align]
[align=left] /// <returns> An instance of the controller if it's type is registered; null if otherwise. </returns>[/align]
[align=left] protected override IController GetControllerInstance( RequestContext requestContext, Type controllerType) {[/align]
[align=left] IController controller;[/align]
[align=left] var workContext = requestContext.GetWorkContext();[/align]
[align=left] if (TryResolve(workContext, controllerType, out controller)) {[/align]
[align=left] return controller;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] // fail as appropriate for MVC's expectations[/align]
[align=left] return base .GetControllerInstance(requestContext, controllerType);[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] [/align]
三、ActionInvoker
在成功创建Controller实例后,会将其ActionInvoker设置成Orchard.Mvc.FilterResolvingActionInvoker。
我们知道,ASP.NET MVC中,我们可以将Filter以Attribute的形式定义在Controller或Action上。Orchard提供了一个Filter Provider机制,即可以将一些Filter定义在其他地方,在使用Filter之前再提取出来。这方面比较简单,直接看FilterResolvingActionInvoker的定义:

[align=left] // 以下代码来在Orchard.Mvc.Filters.FilterResolvingActionInvoker类[/align]

[align=left] public class FilterResolvingActionInvoker : ControllerActionInvoker {[/align]
[align=left] private readonly IEnumerable< IFilterProvider> _filterProviders;[/align]
[align=left] [/align]
[align=left] public FilterResolvingActionInvoker(IEnumerable <IFilterProvider> filterProviders) {[/align]
[align=left] _filterProviders = filterProviders;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {[/align]
[align=left] var filters= base .GetFilters(controllerContext, actionDescriptor);[/align]
[align=left] foreach(var provider in _filterProviders) {[/align]
[align=left] provider.AddFilters(filters);[/align]
[align=left] }[/align]
[align=left] return filters;[/align]
[align=left] }[/align]
[align=left] }[/align]

只要一个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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: