在上一篇"ASP.NET MVC請求處理管道生命週期的19個關鍵環節(7-12) ",體驗了7-12關鍵環節,本篇繼續。html
⒀當請求到達UrlRoutingModule的時候,UrlRoutingModule取出請求中的Controller、Action等RouteData信息,與路由表中的全部規則進行匹配,若匹配,把請求交給IRouteHandler,即MVCRouteHandleride
MVCRouteHandler是用來生成實現IHttpHandler接口的MvcHandler:
函數
namespace System.Web.Routing { public interface IRouteHandler { IHttpHandler GetHttpHandler(RequestContext requestContext); } }
UrlRoutingModule如何把請求交給MVCRouteHandler?
經過分析UrlRoutingModule的源碼能夠看到:ui
//經過RouteCollection的靜態方法GetRouteData獲取到封裝路由信息的RouteData實例
RouteData routeData = this.RouteCollection.GetRouteData(context);this
//再從RouteData中獲取MVCRouteHandler
IRouteHandler routeHandler = routeData.RouteHandler;url
爲何能夠從RouteData中拿到MVCRouteHadnler呢?
由於當咱們在HttpApplication的第一個管道事件,使用MapRoute()方法註冊路由的時候,已經經過Route類的構造函數把MVCRouteHandler注入到路由中了。spa
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) { if (routes == null) { throw new ArgumentNullException("routes"); } if (url == null) { throw new ArgumentNullException("url"); } Route route = new Route(url, new MvcRouteHandler()) { Defaults = new RouteValueDictionary(defaults), Constraints = new RouteValueDictionary(constraints), DataTokens = new RouteValueDictionary() }; if ((namespaces != null) && (namespaces.Length > 0)) { route.DataTokens["Namespaces"] = namespaces; } routes.Add(name, route); return route; }
⒁MVCRouteHandler把請求交給MvcHandler3d
仍是從UrlRoutingModule的源碼能夠看到,經過HttpHandler的GetHttpHandler()方法獲取到了實現了IHttpHandler接口的MVCHandler:code
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
context.RemapHandler(httpHandler);
MvcHandler的部分源碼爲:orm
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState { protected internal virtual void ProcessRequest(HttpContextBase httpContext) { SecurityUtil.ProcessInApplicationTrust(() => { IController controller; IControllerFactory factory; ProcessRequestInit(httpContext, out controller, out factory);//初始化了ControllerFactory try { controller.Execute(RequestContext); } finally { factory.ReleaseController(controller); } }); } private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) { bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(HttpContext.Current); if (isRequestValidationEnabled == true) { ValidationUtility.EnableDynamicValidation(HttpContext.Current); } AddVersionHeader(httpContext); RemoveOptionalRoutingParameters(); string controllerName = RequestContext.RouteData.GetRequiredString("controller"); factory = ControllerBuilder.GetControllerFactory(); controller = factory.CreateController(RequestContext, controllerName); if (controller == null) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,MvcResources.ControllerBuilder_FactoryReturnedNull,factory.GetType(),controllerName)); } } }
⒂從以上能夠看出:首先經過ControllerBuilder的靜態方法GetControllerFactory獲取到實現IControllerFactory接口的ControllerFactory,而後根據從上下文中的路由數據中拿到controller名稱,並據此建立實現IController接口的Controller
Controller派生於ControllerBase, 而ControllerBase實現了IController接口。ControllerBase的部分源碼以下:
public abstract class ControllerBase : IController { protected virtual void Execute(RequestContext requestContext) { if (requestContext == null) { throw new ArgumentNullException("requestContext"); } if (requestContext.HttpContext == null) { throw new ArgumentException( MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, "requestContext"); } VerifyExecuteCalledOnce(); Initialize(requestContext); using (ScopeStorage.CreateTransientScope()) { ExecuteCore(); } } protected abstract void ExecuteCore(); ...... }
從中能夠當作:
● 每次調用controller,都會執行基類ControllerBase的Execute()方法
● Execute()方法又會調用ExecuteCore()這個抽象方法
● ExecuteCore()這個抽象方法的實現被定義在Controller中
● 在Controller中的ExecuteCore()方法會調用ActionInvoker的InvokeAction()方法
⒃ActionInvoker激發Action方法
ActionInvoker實現了IActionInvoker接口:
public interface IActionInvoker { bool InvokeAction(ControllerContext controllerContext, string actionName); }
MVC默認的ActionInvoker是ControllerActionInvoker。
在Controller類中,提供了類型爲IActionInvoker的屬性ActionInvoker,當執行ExecuteCore()方法時會讓這個ActionInvoker調用InvokeAction()方法激發Action。以下:
public class Controller { ...... private IActionInvoker _actionInvoker; public IActionInvoker ActionInvoker { get { if(_actionInvoker == null) { _actionInvoker = CreateActionInvoker(); } return _actionInvoker; } set { _actionInvoker = value; } } protected virtual IActionInvoker CreateActionInvoker() { return new ControllerActionInvoker(); } public override void ExecuteCore() { ActionInvoker.InvokeAction(...); } ..... }
ActionInvoker在執行InvokeAction()方法時會須要有關Controller和Action的相關信息,實際上,Controller信息(好比Controller的名稱、類型、包含的Action等)被封裝在ControllerDescriptor這個類中,Action信息(好比Action的名稱、參數、屬性、過濾器等)被封裝在ActionDescriptor中。
另外,ActionDescriptor還提供了一個FindAction()方法,用來找到須要被執行的Action。
⒄ActionInvoker在執行InvokeAction()方法返回ActionResult
ActionResult是一個抽象類:
public abstract class ActionResult { public abstract void ExecuteResult(ControllerContext context); }
若是ActionResult是非ViewResult,好比JsonResult, ContentResult,這些內容將直接被輸送到Response響應流中,顯示給客戶端;若是是ViewResult,就會進入下一個渲染視圖環節。
⒅ViewEngine找到須要被渲染的視圖
默認的有Razor View Engine和Web Form View Engine,實現IViewEngine接口。
IViewEngine接口方法:
● FindPartialView
● FindView
● ReleaseView
若是要建立自定義View Engine,只須要派生於VirtualPathProviderViewEngine這個類。
⒆View被加載成WebViewPage<TModel>類型,並渲染生成Html
調用ViewResult的ExecuteResult()方法,經過IView的Render()方法渲染成Html。
public abstract class ViewResultBase : ActionResult { public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (String.IsNullOrEmpty(ViewName)) { ViewName = context.RouteData.GetRequiredString("action"); } ViewEngineResult result = null; if (View == null) { //經過視圖引擎獲取到ViewEngineResult ,此時模板頁面【aspx】被加載成了WebViewPage<TModel> result = FindView(context); View = result.View; } TextWriter writer = context.HttpContext.Response.Output; ViewContext viewContext = new ViewContext(context, View, ViewData, TempData, writer); View.Render(viewContext, writer); if (result != null) { result.ViewEngine.ReleaseView(context, View); } } }
ASP.NET MVC請求處理管道生命週期的19個關鍵環節系列包括: