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其实ASP.NET 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实例的创建过程,从中可以看出ASP.NET MVC框架定义很多的扩展点,
下一节我们来看看具体Controller激活相关的扩展应用。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。