ASP.NET MVC請求處理管道生命週期的19個關鍵環節(13-19)

來源:互聯網
上載者:User

標籤:des   style   class   blog   code   http   

在上一篇"ASP.NET MVC請求處理管道生命週期的19個關鍵環節(7-12) ",體驗了7-12關鍵環節,本篇繼續。

 

  ⒀當請求到達UrlRoutingModule的時候,UrlRoutingModule取出請求中的Controller、Action等RouteData資訊,與路由表中的所有規則進行匹配,若匹配,把請求交給IRouteHandler,即MVCRouteHandler

 

MVCRouteHandler是用來產生實現IHttpHandler介面的MvcHandler:

namespace System.Web.Routing{      public interface IRouteHandler    {               IHttpHandler GetHttpHandler(RequestContext requestContext);    }}

UrlRoutingModule如何把請求交給MVCRouteHandler?
通過分析UrlRoutingModule的源碼可以看到:

//通過RouteCollection的靜態方法GetRouteData擷取到封裝路由資訊的RouteData執行個體
RouteData routeData = this.RouteCollection.GetRouteData(context);

 

//再從RouteData中擷取MVCRouteHandler
IRouteHandler routeHandler = routeData.RouteHandler;

 

為什麼可以從RouteData中拿到MVCRouteHadnler呢?
因為當我們在HttpApplication的第一個管道事件,使用MapRoute()方法註冊路由的時候,已經通過Route類的建構函式把MVCRouteHandler注入到路由中了。

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把請求交給MvcHandler

 

還是從UrlRoutingModule的源碼可以看到,通過HttpHandler的GetHttpHandler()方法擷取到了實現了IHttpHandler介面的MVCHandler:

IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);context.RemapHandler(httpHandler);

 

MvcHandler的部分源碼為:

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);            }        }}

completed~~

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.