MVC Controller的激活
各Controller的继承关系
Controller最重要的是对Execute方法的调用,当目标Controller对象被激活后,对请求的后续处理和最终响应均是通过执行这个Execute方法来完成。它就定义在IController接口中,如下所示:
public interface IController { void Execute(RequestContext requestContext); }
由于定义在IController接口的Execute方法是以同步的方式执行的,为了异步方式,又另定义了一个IAsyncController接口,它派生于IController接口,Controller的异步执行通过先后调用BeginExecute/EndExecute方法来完成。如下所示:
public interface IAsyncController : IController { IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state); void EndExecute(IAsyncResult asyncResult); }
默认作为所有Controller基类的ControllerBase实现了IController接口,ControllerBase是一个抽像类,它“显示”的实现了IController中的Execute方法,然后它会调用这个类中受保护的虚方法Execute,而后者最终又会调用抽象方法ExecuteCore。如下所示:
public abstract class ControllerBase : IController { //省略 public ControllerContext ControllerContext { get; set; } void IController.Execute(RequestContext requestContext) { Execute(requestContext); } protected virtual void Execute(RequestContext requestContext) { //省略 VerifyExecuteCalledOnce(); Initialize(requestContext); using (ScopeStorage.CreateTransientScope()) { ExecuteCore(); } } protected abstract void ExecuteCore(); protected virtual void Initialize(RequestContext requestContext) { ControllerContext = new ControllerContext(requestContext, this); } //省略 }
从上面我们可以看到受保护的虚方法Execute在调ExecuteCore抽像方法之前,会执行受保护的虚方法Initialize方法初始化ControllerContext属性。ControllerContext如下所示:
public class ControllerContext { public virtual ControllerBase Controller { get; set; } public virtual HttpContextBase HttpContext { get { if (_httpContext == null) { _httpContext = (_requestContext != null) ? _requestContext.HttpContext : new EmptyHttpContext(); } return _httpContext; } set { _httpContext = value; } } public virtual RouteData RouteData { get { if (_routeData == null) { _routeData = (_requestContext != null) ? _requestContext.RouteData : new RouteData(); } return _routeData; } set { _routeData = value; } } public RequestContext RequestContext { get { if (_requestContext == null) { // still need explicit calls to constructors since the property getters are virtual and might return null HttpContextBase httpContext = HttpContext ?? new EmptyHttpContext(); RouteData routeData = RouteData ?? new RouteData(); _requestContext = new RequestContext(httpContext, routeData); } return _requestContext; } set { _requestContext = value; } } public ControllerContext(HttpContextBase httpContext, RouteData routeData, ControllerBase controller) : this(new RequestContext(httpContext, routeData), controller) { } public ControllerContext(RequestContext requestContext, ControllerBase controller) { //省略 RequestContext = requestContext; Controller = controller; } }
顾名思义,ControllerContext就是基于某个Controller对象上下文。从上面我们可以看出ControllerContext主要是对Controller、RequestContext对象的封装。而对RequestContext又是对HttpContext和RouteData的封装。
VS帮我们创建的Controller默认都是继承自抽像类Controller,它是ControllerBase的子类,如下所示:
public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer { protected virtual bool DisableAsyncSupport { get { return false; } } IAsyncResult IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, object state) { return BeginExecute(requestContext, callback, state); } void IAsyncController.EndExecute(IAsyncResult asyncResult) { EndExecute(asyncResult); } protected virtual IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state) { if (DisableAsyncSupport) { //同步 Action action = () => { Execute(requestContext); }; //省略 } else { //异步 //省略 } } protected virtual void EndExecute(IAsyncResult asyncResult) { AsyncResultWrapper.End(asyncResult, _executeTag); } } public interface IAsyncManagerContainer { AsyncManager AsyncManager { get; } }
Controller还显示地实现了IAsyncController接口和ASP.NET MVC 5种过虑器接口,以及一个特别的IAsyncManagerContainer接口,它提供了一个AsyncManger对象为异步操作的执行提供参数传递操作计数和超时控制等功能,除此之外Controller还为我们实现IDispose接口,在Controller执行结束之后会调用其Dispose方法以完成相应的资源回收工作。
从抽像类Controller的定义上来看,它实现了IAsyncController,而IAsyncController继承自IController,这意味着它既可以采用同步(调用Execute方法)又可以采用异步(调用BeginExecute/EndExecute)的方法执行。但是调用BeginExecute/EndExecute方法也不一定是以异步的方式执行。如上代码所示中它有一个DisableAsyncSupport属性,它默认值为False。
在ASP.NET MVC中还定义了一个AsyncController类,从名称上我们可以看出这是一个异步Controller。但这里指的是Action方法的异步,而不是Controller的异步执行。如下所示:
public abstract class AsyncController : Controller { }
这是一个继承自抽像类Controller的一个“空”类型,因为在ASP.NET MVC 3.0时,异步的执行是通过XxxAsync/XxxCompleted的形式定义,以这种方式定义的异步Action方法必须定义在继承自AsyncController的类型中。考虑到向后兼容,于是就一直保留了下来。不过在 ASP.NET MVC4.0及以后,提供了新的异步Action方法定义方式。它直接定义在我们创建的继承自抽像Controller类的子类Controller中就好了,Action方法返回类型为Task既可。
Controller的激活
首先来看一下IControllerFactory接口,如下所示:
public interface IControllerFactory { IController CreateController(RequestContext requestContext, string controllerName); SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName); void ReleaseController(IController controller); }
从上代码我们看到Controller对象的激活最终是通过CreateController方法来完成的。除了负责创建Controller对象外,还需要处理Controller对象的释放,这个定义在ReleaseController方法中。IControllerFactory还定义一个方法 GetControllerSessionBehavior,返回一个枚举类型SessionStateBehavior,它表示请求处理过程中会话状态支持的模式。具体采用何种会话状态模式取决于当前HTTP上下文(通过HttpContext的静态属性Current表示)。在 ASP.NET 3.0及之前的版本,我们是不能对当前HttpContext会话状态模式进行动态修改。ASP.NET 4.0为HttpContext定义了如下SetSessionStateBehavior方法,相同的方法在HttpContextBase、HttpContextWrapper都有定义。
public abstract class HttpContextBase : IServiceProvider { public virtual void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior) { } } public class HttpContextWrapper : HttpContextBase { public override void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior) { this._context.SetSessionStateBehavior(sessionStateBehavior); } } public sealed class HttpContext : IServiceProvider, IPrincipalContainer { public void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior) { //省略 this.SessionStateBehavior = sessionStateBehavior; } }
用于激活Controller对象的ControllerFactory最终是通过ControllerBuilder注册到MVC框架中的,代码如下:
public class ControllerBuilder { private static ControllerBuilder _instance = new ControllerBuilder(); public static ControllerBuilder Current { get { return _instance; } } public ControllerBuilder(): this(null) { } internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver) { _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>( () => _factoryThunk(), new DefaultControllerFactory { ControllerBuilder = this }, "ControllerBuilder.GetControllerFactory"); } public void SetControllerFactory(IControllerFactory controllerFactory) { //省略 _factoryThunk = () => controllerFactory; } public void SetControllerFactory(Type controllerFactoryType) { //省略 _factoryThunk = delegate { return (IControllerFactory)Activator.CreateInstance(controllerFactoryType); }; } public IControllerFactory GetControllerFactory() { return _serviceResolver.Current; } }
从上代码片段中,我们可以看到一个Current属性返回当前使用的ControllerBuilder对象,以及两个SetControllerFactory方法重载实现针对ControllerFactory的注册和一个GetControllerFactory方法用于获取ControllerFactory对象。 关于两个重载方法,它们的不同之处在于第一个是传入一个IControllerFactory对象,第二个是传入一个IControllerFactory类型。如果是通过第二个的方法注册ControllerFactory,那么我们在每次获取时,都要通过反射获得某个ControllerFactory的实例,MVC将不会对它所创建的Controller进行缓存。而第一个则直接将IControllerFactory对象返回。从性能方面考虑,第一种的方式更好一些,在构造函数中我们也可以看到默认就是通过new一个DefaultControllerFactory对象。
在《简说mvc路由》一文中我们介绍过MVC是通过UrlRoutingModule对HttpApplication上的PostResovleRequestCache事件的注册拦截请求。然后从RouteTable的静态属性Routes中对请求实施路由解析生成一个RouteData对象,然后借助RouteData的RouteHandler属性得到最终的被映射到当前请求的HttpHandler。
public class MvcRouteHandler : IRouteHandler { private IControllerFactory _controllerFactory; public MvcRouteHandler() { } public MvcRouteHandler(IControllerFactory controllerFactory) { _controllerFactory = controllerFactory; } protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext)); return new MvcHandler(requestContext); } protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext) { string controllerName = (string)requestContext.RouteData.Values["controller"]; //省略 IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory(); return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName); } }
在上一篇文章中,我们知道MVC框架中,对RouteHandler默认实现就是MvcRouteHandler。在MvcRouteHandler中维护着一个ControllerFactory对象,该对象可以在构造函数中指定,如果没有指定,那么它会调用当前ControllerBuilder对象GetControllerFactory方法得到这个对象。在实例化Route时,我们传的是new MvcRouteHandler()时,是调用无参构造函数的,所以在这里_controllerFactory肯定为null,而在上面ControllerBuilder类的代码片段中,Current是通过new了一个ControllerBuilder无参构造函数,所以MVC默认ControllerFactory的实现是DefaultControllerFactory。不过这里获得ControllerFactory只是用于设置会话状态方式。真正获得ControllerFactory用于创建Controller对象体现在MvcHandler的BeginProcessRequest方法中。
接下来我们主要看IHttpHandler的实现类MvcHandler,如下所示:
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState { internal ControllerBuilder ControllerBuilder { get { if (_controllerBuilder == null) { _controllerBuilder = ControllerBuilder.Current; } return _controllerBuilder; } set { _controllerBuilder = value; } } protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) { IController controller; IControllerFactory factory; ProcessRequestInit(httpContext, out controller, out factory); IAsyncController asyncController = controller as IAsyncController; if (asyncController != null) { // asynchronous controller // Ensure delegates continue to use the C# Compiler static delegate caching optimization. BeginInvokeDelegate<ProcessRequestState> beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState, ProcessRequestState innerState) { try { return innerState.AsyncController.BeginExecute(innerState.RequestContext, asyncCallback, asyncState); } catch { innerState.ReleaseController(); throw; } }; EndInvokeVoidDelegate<ProcessRequestState> endDelegate = delegate(IAsyncResult asyncResult, ProcessRequestState innerState) { try { innerState.AsyncController.EndExecute(asyncResult); } finally { innerState.ReleaseController(); } }; ProcessRequestState outerState = new ProcessRequestState() { AsyncController = asyncController, Factory = factory, RequestContext = RequestContext }; SynchronizationContext callbackSyncContext = SynchronizationContextUtil.GetSynchronizationContext(); return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, outerState, _processRequestTag, callbackSyncContext: callbackSyncContext); } else { // synchronous controller Action action = delegate { try { controller.Execute(RequestContext); } finally { factory.ReleaseController(controller); } }; return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag); } } private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) { //省略 string controllerName = RequestContext.RouteData.GetRequiredString("controller"); //省略 factory = ControllerBuilder.GetControllerFactory(); controller = factory.CreateController(RequestContext, controllerName); //省略 } }
从上我们可以看到MvcHandler同时实现了IHttpAsyncHandler和IHttpHandler接口,所以它总是以异步的方式被执行(调用BeginProcessRequest和EndProcessRequest方法)。调用ProcessRequestInit方法中,通过RequestContext的RouteData属性获得controller名称,然后通过本类的ControllerBuilder属性获得ControllerFactory类的实例factory,然后通过它获得Controller的对象,然后调用Controller中的Execute方法或异步BeginExecute/EndExecute方法。
关于DefaultControllerFactory创建Controller如下所示:
public class DefaultControllerFactory : IControllerFactory { private IControllerActivator ControllerActivator { get { if (_controllerActivator != null) { return _controllerActivator; } _controllerActivator = _activatorResolver.Current; return _controllerActivator; } } public virtual IController CreateController(RequestContext requestContext, string controllerName) { if (requestContext == null) { throw new ArgumentNullException("requestContext"); } if (String.IsNullOrEmpty(controllerName) && !requestContext.RouteData.HasDirectRouteMatch()) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName"); } Type controllerType = GetControllerType(requestContext, controllerName); IController controller = GetControllerInstance(requestContext, controllerType); return controller; } protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType) { //省略 return ControllerActivator.Create(requestContext, controllerType); } //省略 }
本文来自博客园,作者:追夢,转载请注明原文链接:https://www.cnblogs.com/koeltp/p/7406928.html