• ASP.NET MVC请求处理管道生命周期的19个关键环节(13-19)


    转自:http://www.cnblogs.com/darrenji/p/3795690.html

    在上一篇"ASP.NET MVC请求处理管道生命周期的19个关键环节(7-12) ",体验了7-12关键环节,本篇继续。

      ⒀当请求到达UrlRoutingModule的时候,UrlRoutingModule取出请求中的Controller、Action等RouteData信息,与路由表中的所有规则进行匹配,若匹配,把请求交给IRouteHandler,即MVCRouteHandler

    13

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

    14

    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

    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)

  • 相关阅读:
    [记录]Eclipse版本选择和安装
    Nexus+Maven安装配置手册
    Eclipse编写Java程序
    Tomcat下载和配置
    SQL Server如何清除连接过的服务器名称历史?
    为文本添加全选Ctrl + A 功能
    配置Eclipse使用TFS源码管理
    [jQuery] jSrcollable
    [ios] cocos2d/cocos2dx 演示
    [c++] 实现类似printf这样的函数
  • 原文地址:https://www.cnblogs.com/cxzdy/p/3809234.html
Copyright © 2020-2023  润新知