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

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

 

  ⒀當請求到達UrlRoutingModule的時候,UrlRoutingModule取出請求中的Controller、Action等RouteData信息,與路由表中的全部規則進行匹配,若匹配,把請求交給IRouteHandler,即MVCRouteHandleride

13

 

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

14

 

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

15

 

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方法

16

 

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

17

 

ActionResult是一個抽象類:

public abstract class ActionResult
{
  public abstract void ExecuteResult(ControllerContext context);
}

若是ActionResult是非ViewResult,好比JsonResult, ContentResult,這些內容將直接被輸送到Response響應流中,顯示給客戶端;若是是ViewResult,就會進入下一個渲染視圖環節。

 

  ⒅ViewEngine找到須要被渲染的視圖

18

 

默認的有Razor View Engine和Web Form View Engine,實現IViewEngine接口。

 

IViewEngine接口方法:
● FindPartialView
● FindView
● ReleaseView

 

若是要建立自定義View Engine,只須要派生於VirtualPathProviderViewEngine這個類。

 

  ⒆View被加載成WebViewPage<TModel>類型,並渲染生成Html

19

 

調用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個關鍵環節系列包括:

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

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

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

相關文章
相關標籤/搜索