各Controller的繼承關係html
Controller最重要的是對Execute方法的調用,當目標Controller對象被激活後,對請求的後續處理和最終響應均是經過執行這個Execute方法來完成。它就定義在IController接口中,以下所示:緩存
public interface IController { void Execute(RequestContext requestContext); }
因爲定義在IController接口的Execute方法是以同步的方式執行的,爲了異步方式,又另定義了一個IAsyncController接口,它派生於IController接口,Controller的異步執行經過前後調用BeginExecute/EndExecute方法來完成。以下所示:session
public interface IAsyncController : IController { IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state); void EndExecute(IAsyncResult asyncResult); }
默認做爲全部Controller基類的ControllerBase實現了IController接口,ControllerBase是一個抽像類,它「顯示」的實現了IController中的Execute方法,而後它會調用這個類中受保護的虛方法Execute,然後者最終又會調用抽象方法ExecuteCore。以下所示:mvc
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以下所示:app
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方法以完成相應的資源回收工做。async
從抽像類Controller的定義上來看,它實現了IAsyncController,而IAsyncController繼承自IController,這意味着它既能夠採用同步(調用Execute方法)又能夠採用異步(調用BeginExecute/EndExecute)的方法執行。可是調用BeginExecute/EndExecute方法也不必定是以異步的方式執行。如上代碼所示中它有一個DisableAsyncSupport屬性,它默認值爲False。ide
在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); } //省略 }