300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > ASP.NET MVC4学习笔记之Controller的激活

ASP.NET MVC4学习笔记之Controller的激活

时间:2024-02-17 19:07:48

相关推荐

ASP.NET MVC4学习笔记之Controller的激活

一.高层相关类说明

当路由系统根据请求Url收集路由信息后,下一步就要将路由信息传给Controller激活系统,Controller激活系统负责实现了IController接口的Controller类实例化。它的相关类族体系如下图所示:

MvcHandler实现了IHttpHandler,IHttpAsyncHandler,IRequiresSessionState三个接口,其中IHttpHandler,IHttpAsyncHandler分别是HttpHandler同步与异步的实现,IRequiresSessionState是个标记接口,表示需要Session支持.

IController, IAsyncController,ControllerBase, Controller是一个继承体系,IController是控制器接口,只定义了一个方法Execute方法表示执行入口,

IAsyncController是控制器的异步执行版本,ControllerBase是控制器基类,为控制器执行做一些初始化和环境准备工作,实现了Execute方法并在其内调用保护的抽像方法ExecuteCore.这个地方应用了Templete Method模式.Controller实现了一堆接口, 为我们编程提供方便,定义了大量的属性和方法,具体的后面章节专门讲解.

IControllerFactory表示的是控制器的创建工厂,其中定义了三个方法,CreateController方法创建IController的实例,GetControllerSessionBehavior方法获取Controller的会话行为,我们可以在自定义的Controller的上应用SessionStateAttribute指定会话行为。ReleaseController负责释放使用完的Controller实例。

public interface IControllerFactory

{

IController CreateController(RequestContext requestContext, string controllerName);

SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);

void ReleaseController(IController controller);

}

ControllerBuilder是负责实例化IController和IControllerFactory的接口,封装具体的创建算法。提供了一个静态只读属性Current表示当前的ControllerBuilder对象。

二. MvcHandler中IController与IControllerFactory的创建与执行

1. 主体过程ProcessRequest方法,代码如下所示, 创建的过程委托给私有方法ProcessRequestInit

protected internal virtual void ProcessRequest(HttpContextBase httpContext)

{

IController controller;

IControllerFactory factory;

ProcessRequestInit(httpContext, out controller, out factory);

try

{

controller.Execute(RequestContext);

}

finally

{

factory.ReleaseController(controller);

}

}

2.ProcessRequestInit方法的主要代码如下所示,我们可以看到最终的创建工作是交给了ControllerBuilder对象.

private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)

{

//其它代码

// Get the controller type

string controllerName = RequestContext.RouteData.GetRequiredString("controller");

// Instantiate the controller and call Execute

factory = ControllerBuilder.GetControllerFactory();

controller = factory.CreateController(RequestContext, controllerName);

if (controller == null)

{

throw new InvalidOperationException(...)

}

}

三.ControllerBuilder解析

1.接口定义如下:

public class ControllerBuilder

{

public ControllerBuilder();

public static ControllerBuilder Current { get; } //

public HashSet<string> DefaultNamespaces { get; } //默认命名空间,用于Controller类型解析过程

public IControllerFactory GetControllerFactory();

public void SetControllerFactory(IControllerFactory controllerFactory); //设置自定义ControllerFactory

public void SetControllerFactory(Type controllerFactoryType); //设置自定义ControllerFactory的类型,

}

ControllerBuilder主要封装了IControllerFactory的创建过程,也许命名叫ControllerFactoryBuilder更合适,从接口可以看出,我们可以传入自定义

实现的IControllerFactory。

2. 内部引用的几个主要类说明:

IResolver<T> 只定义了一个泛型属性,表示获取相关类型的一个实例;

SingleServiceResolver<TService> 顾名思义,表示单一服务类型解析,它实现在了IResolver接口, 在ControllerBuilder内部使用的是SingleServiceResolver<IControllerFactory>;

DefaultControllerFactory 系统提供的默认的Controller创建工厂实现;

3. 内部IControllerFactory创建过程

在ControllerBuilder实例化时,调用默认构造函数,而默认构造函数调用如下的内部构造函数,serviceResolver传值为null,

internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)

{

_serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(

() => _factoryThunk(),

new DefaultControllerFactory { ControllerBuilder = this },

"ControllerBuilder.GetControllerFactory");

}

_factoryTunk() 是一个返回IControllerFactory的委托(Func<IControllerFactory>),默认值是() => null; 其主要目的是当传入自定义IControllerFactory时做统一处理,

public void SetControllerFactory(IControllerFactory controllerFactory)

{

_factoryThunk = () => controllerFactory;

}

ControllerBuilder返回IControllerFactory的方法内部实现如下:

public IControllerFactory GetControllerFactory()

{

return _serviceResolver.Current;

}

从上面的代码中我们可以看出Factory的创建过程进一步委托给了SingleServiceResolver对象,现在我们看看SingleServiceResolver究竟是怎么创建对象的

.SingleServiceResolver<TService> 类型

SingleServiceResolver其实 MVC许多基础类型创建所遵询的一个模式. 它的构造函数如下:

public SingleServiceResolver(Func<TService> currentValueThunk, TService defaultValue, string callerMethodName)

{

//省略检查代码

_resolverThunk = () => DependencyResolver.Current; //DependencyResolver.Current表示系统全局的对象解析器

_currentValueFromResolver = new Lazy<TService>(GetValueFromResolver); //从全局的Resolver器中创建对象

_currentValueThunk = currentValueThunk; //当前传入的创建委托

_defaultValue = defaultValue; //默认值

_callerMethodName = callerMethodName;

}

返回实例的代码如下

public TService Current

{

get { return _currentValueFromResolver.Value ?? _currentValueThunk() ?? _defaultValue; }

}

从中我们可以看出SingleServiceResolver解析对象的过程:

1. 首先从尝试从全局的对象解析器(DependencyResolver)中创建对象

2. 否则尝试利用当前的功能委托来创建对象

3. 最后返回对象的默认值

在IControllerFactory创建中,默认情况下第1种和第2种情况都不起作用,所以返回的是DefaultControllerFactory, 现在我们终于得到了IControllerFactory实例,现在来看看它是怎么生成Controller实例的。

五.DefaultControllerFactory解析

DefaultControllerFactory实现了IControllerFactory, 故名思义,它的主要作用就是Controller实例的创建与释放,会话模式的获取。

1. Controller类型的实例化

Controller实例的创建实现在CreateController方法中,主要的代码如下:

public virtual IController CreateController(RequestContext requestContext, string controllerName)

{

//省略其它代码

Type controllerType = GetControllerType(requestContext, controllerName);

IController controller = GetControllerInstance(requestContext, controllerType);

return controller;

}

可以看到分成了两步走,首先查找确定Controller的类型,接着再利用类型创建其实例。下面来具体的看看相关的方法

1.1 Controller类型的查找

类型的查找实现在GetControllerType方法中,代码如下:

protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName)

{

// 省略其它代码

//1. 首先检查在定制路由规则时指定的命名空间

object routeNamespacesObj;

Type match;

if (requestContext != null && routeData.DataTokens.TryGetValue(RouteDataTokenKeys.Namespaces, out routeNamespacesObj))

{

IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>;

if (routeNamespaces != null && routeNamespaces.Any())

{

HashSet<string> namespaceHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase);

match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceHash);

// the UseNamespaceFallback key might not exist, in which case its value is implicitly "true"

if (match != null || false.Equals(routeData.DataTokens[RouteDataTokenKeys.UseNamespaceFallback]))

{

// got a match or the route requested we stop looking

return match;

}

}

}

// 检查默认的命名空间

if (ControllerBuilder.DefaultNamespaces.Count > 0)

{

HashSet<string> namespaceDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);

match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceDefaults);

if (match != null)

{

return match;

}

}

//检查所有的命名空间,也就是只要有Controller名唯一匹配的就返回相应的Controller类型

return GetControllerTypeWithinNamespaces(routeData.Route, controllerName, null /* namespaces */);

}

这个方法是查找Controller类型的骨架,查找是由三个层次的命名空间组成,

1.首先从制定路由规则时指定的命名空间中查找,但一般我们指定路由规则时没有指定命名空间,这里有还有一个参数UseNamespaceFallback表示是否查找后备命名空间,这个参数默认为true.

2. 从默认的命名空间ControllerBuilder.DefaultNamespaces中查找

3. 从所有的命名空间中查找,查找唯一能匹配的Controller

在以上查找中,都会调用GetControllerTypeWithinNamespaces方法,现在来看看这个方法的实现

private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces)

{

// Once the master list of controllers has been created we can quickly index into it

ControllerTypeCache.EnsureInitialized(BuildManager);

ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);

switch (matchingTypes.Count)

{

case 0:

// no matching types

return null;

case 1:

// single matching type

return matchingTypes.First();

default:

// multiple matching types

throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);

}

}

从以上的代码中我们可以看到查找工作又进一步委托给了ControllerTypeCache这个内部类型,这个类型是特意为实现快速查找Controller类型而设计的一个数据结构,在内部它把所有的Controller通过反射把数据组织成如下形式:

controllerAName namespace1, Type

namespace2, Type

controllerBName namespace1, Type

namespace2, Type

...

当我们调用ControllerTypeCache.GetControllerTypes,传入controllerName, namespaces参数时,首先会通过controllerName得到匹配的namespace和Type列表,

再利用传入的namespaces参数与列表中的每个namespace进行比较,匹配则将相应的类型加入返回列表,如果传入的namespaces为null, 则直接将列表中所有的类型都加入返回列表,在GetControllerTypeWithinNamespaces方法中我们检查返回结果,如果只有一个类型,这是我们想要的结果,则直接返回,有一个以上则抛出Ambiguous异常。至此我们确定了Controller的类型,现在来看看Controller的实例化。

1.2 Controller类型的实例化

在前面我们已经看到,Controller类型实例化是实现在GetControllerInstance方法中,代码如下:

protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)

{

//省略非关键代码

return ControllerActivator.Create(requestContext, controllerType);

}

直接调用了ControllerActivator来创建实例,ControllerActivator是一个类型为IControllerActivator的属性,IControllerActivator的定义如下:

public interface IControllerActivator

{

IController Create(RequestContext requestContext, Type controllerType);

}

具体来看看ControllerActivator属性的定义,

private IControllerActivator ControllerActivator

{

get

{

if (_controllerActivator != null)

{

return _controllerActivator;

}

_controllerActivator = _activatorResolver.Current;

return _controllerActivator;

}

}

这里_controllerActivator在DefaultControllerFactory构造函数中初始化,代表传入自定义的Controller激活器.具有最高的优先级。

_activatorResolver是IResolver<IControllerActivator>类型, 也是在构造函数中初始化,允许自定义实现IResolver<IControllerActivator>,具有第二高的优先级,

但在默认情况一下,前面两个参数都为null,_activatorResolver被实例化为SingleServiceResolver<IControllerActivator>类型。具体我们来看看DefaultControllerFactory的构造函数:

internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver)

{

if (controllerActivator != null)

{

_controllerActivator = controllerActivator;

}

else

{

_activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(

() => null,

new DefaultControllerActivator(dependencyResolver),

"DefaultControllerFactory constructor");

}

}

SingleServiceResolver<T>泛型类前面已分析,这里不再赘述,从上面的代码中我们看到,默认情况下Controller实例化最终落在了DefaultControllerActivator的头上,

再来看看该类型的实现:

private class DefaultControllerActivator : IControllerActivator

{

private Func<IDependencyResolver> _resolverThunk;

public DefaultControllerActivator()

: this(null)

{

}

public DefaultControllerActivator(IDependencyResolver resolver)

{

if (resolver == null)

{

_resolverThunk = () => DependencyResolver.Current;

}

else

{

_resolverThunk = () => resolver;

}

}

public IController Create(RequestContext requestContext, Type controllerType)

{

try

{

return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));

}

catch (Exception ex)

{

throw new InvalidOperationException(...)

}

}

}

DefaultControllerActivator构造函数允许传一个IDependencyResolver 对象,从上面的代码中我们可以看出,优先使用该对象创建Conroller实例,

如果该对象为null,则尝试使用系统默认的DependencyResolver,如果前面的两者IDependencyResolver创建失败,再使用Activator.CreateInstance实列化.

在默认情况一下,Controller实例是通过DependencyResolver.Current实列化,最终也是调用Activator.CreateInstance实例化的。

2. Controller实例的释放

释放的实现代码很简单,即检查Controller是否实现了IDisposable 接口,如果实现该接口则调用其Dispose()方法。

public virtual void ReleaseController(IController controller)

{

IDisposable disposable = controller as IDisposable;

if (disposable != null)

{

disposable.Dispose();

}

}

3.Controller会话行为的设置

3.1 会话行为获取

controller会话行为的获取是通过反射得到应用在Controller上的SessionStateAttribute,具体的实现在代码在GetControllerSessionBehavior中,

protected internal virtual SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)

{

if (controllerType == null)

{

return SessionStateBehavior.Default;

}

return _sessionStateCache.GetOrAdd(

controllerType,

type =>

{

var attr = type.GetCustomAttributes(typeof(SessionStateAttribute), inherit: true)

.OfType<SessionStateAttribute>()

.FirstOrDefault();

return (attr != null) ? attr.Behavior : SessionStateBehavior.Default;

});

}

从上面的代码中可以看出,如果没在Controller上的指定特别的Session行为,会返回SessionStateBehavior.Default,表示由IHttpHandler实现的会话标记接口来确定会话行为,MvcHandler标记了IRequiresSessionState,表示Session可读可写.

3.2 会话行为设置

会话行为设置是在MvcRouteHandler中,具本的代码如下:

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)

{

//设置会话行为

requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));

return new MvcHandler(requestContext);

}

protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)

{

//省略非关键代码

IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();

return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);

}

六总结

在本小节中,我们在源代码级别分析了ControllerFacotry和Controller实例的创建过程,从中可以看出 MVC框架定义很多的扩展点,

下一节我们来看看具体Controller激活相关的扩展应用。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。