博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET MVC请求处理管道生命周期的19个关键环节(13-19)
阅读量:7010 次
发布时间:2019-06-28

本文共 7259 字,大约阅读时间需要 24 分钟。

在上一篇" ",体验了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
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个关键环节系列包括:

转载地址:http://uvttl.baihongyu.com/

你可能感兴趣的文章
软件架构师应该知道的97件事
查看>>
VMware、Citrix和Microsoft虚拟化技术详解与应用实践
查看>>
SublimeText3使用技巧总结
查看>>
微软称Silverlight技术领先于HTML5
查看>>
SQL SERVER普通用户需要什么权限才能执行sp_configure命令
查看>>
十个开源的Javascript框架
查看>>
Simple guide to Java Message Service (JMS) using ActiveMQ
查看>>
从输入 URL 到页面加载完的过程中都发生了什么事情?
查看>>
PHP——面向对象
查看>>
HashMap与ConcurrentHashMap的区别(转)
查看>>
ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
查看>>
图的理解:深度优先和广度优先遍历及其 Java 实现
查看>>
Linux/Unix shell 监控Oracle告警日志(monitor alter log file)
查看>>
Linux之 find之 ctime,atime,mtime
查看>>
Asp.net mvc 集成Autofac和FluentValidation
查看>>
WinForm企业应用框架设计【一】界限划分与动态创建WCF服务(no svc!no serviceActivations!)...
查看>>
sharepoint 页面使用javascript出错解决办法
查看>>
程序员究竟该如何提高效率【转】
查看>>
UVA 10056 What is the Probability ?
查看>>
DotNet4应用程序打包工具->升级版【三】宿主程序分析+全部源码下载
查看>>