asp.net MVC 应用程序的生命周期(下)

看看上面的UrlRoutingModule源码里面是怎么实现Init方法的,Init()方法里面我标注红色的地方:

 

application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);

 

这一步至关重要哈,看到没有,就是对我们在HttpApplication那19个事件中的PostResolveRequestCache事件的注册。

 

注册的方法是OnApplicationPostResolveRequestCache事件。也就是说HttpApplication对象在执行到PostResolveRequestCache这个事件的时候,就会执行OnApplicationPostResolveRequestCache事件。决定是MVC机制处理请求的关键所在就是OnApplicationPostResolveRequestCache事件。

 

从源码中我们看出,OnApplicationPostResolveRequestCache事件执行的时候,最终执行了PostResolveRequestCache这个方法。最关键的地方呢就在这里了。

 

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

 

我们可以看下UrlRoutingModule的源码来看看,以下是几句核心的代码:

 

我们再分析一下这个方法的源码:

 

public virtual void PostResolveRequestCache(HttpContextBase context)

{

    // 通过RouteCollection的静态方法GetRouteData获取到封装路由信息的RouteData实例

    RouteData routeData = this.RouteCollection.GetRouteData(context);

    if (routeData != null)

    {

        // 再从RouteData中获取MVCRouteHandler

        IRouteHandler routeHandler = routeData.RouteHandler;

        ......

        if (!(routeHandler is StopRoutingHandler))

        {

            ......

            // 调用 IRouteHandler.GetHttpHandler(),获取的IHttpHandler 类型实例,它是由 IRouteHandler.GetHttpHandler获取的,这个得去MVC的源码里看

            IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

            ......

            // 合适条件下,把之前将获取的IHttpHandler 类型实例 映射到IIS HTTP处理管道中

            context.RemapHandler(httpHandler);

        }

    }

}

 

看到了吧,通过路由规则,返回的不为空,说明匹配正确,关于路由规则的匹配,说起来也不短,这里就不大幅介绍,有时间下次再开篇详解路由机制。匹配成功后,返回一个RouteData类型的对象,RouteData对象都有些什么属性呢?看看这行源码: IRouteHandler routeHandler = routeData.RouteHandler;或者看源码我们知道,RouteDate有一个RouteHandler属性。

 

 

那么UrlRouting Module是如何选择匹配规则的呢?

 

 

我们看看我们新建的MVC应用程序,在App_Start文件夹下面有一个RouteConfig.cs类,这个类的内容如下:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using System.Web.Routing;

 

namespace ApiDemo

{

    public class RouteConfig

    {

        public static void RegisterRoutes(RouteCollection routes)

        {

            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 

            routes.MapRoute(

                name: "Default",

                url: "{controller}/{action}/{id}",

                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

            );

        }

    }

}

 

我们在这个类里面,主要是给路由表添加路由规则。在看看上面的UrlRoutingModule类,里面有一个RoutCollection属性,所以UrlRoutingModule能够获取路由表中的所有规则,这里值得注意的是,路由规则的匹配是有顺序的,如果有多个规则都能够匹配,UrlRoutingModule至选择第一个匹配的规则就返回,不再继续往下匹配了。相反的如果一个请求,没有匹配到任何路由,那么该请求就不会被处理。

 

这里返回的RouteData里的RouteHandler就是MVCRouteHandler。为什么呢?那我们继续往下看RouteHandler。

 

RouteHandler                                                        

 

生成MvcHander

 

在上面路由匹配的过程中,与匹配路由相关联的MvcRouteHandler ,MvcRouteHandler 实现了IRouteHandler 接口。

 

MvcRouteHandler 主要是用来获取对MvcHandler的引用。MvcHandler实现了IhttpHandler接口。

 

MVCRouteHandler的作用是用来生成实现IHttpHandler接口的MvcHandler。而我们前面说过最终处理请求的都是相对应的HttpHandler。

 

那么处理MVC请求的自然就是这个MvcHandler。所以这里返MvcRouteHandler至关重要:

 

那么,MvcRouteHandler从何而来呢?众所周知,ASP.NET MVC项目启动是从Global中的Application_Start()方法开始的,那就去看看它:

 

public class MvcApplication : System.Web.HttpApplication

    {

        protected void Application_Start()

        {

 

            RouteConfig.RegisterRoutes(RouteTable.Routes);

            BundleConfig.RegisterBundles(BundleTable.Bundles);

        }

    }

 

    public class RouteConfig

    {

        public static void RegisterRoutes(RouteCollection routes)

        {

            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

System.Web.Mvc.RouteCollectionExtensions

            routes.MapRoute(

                name: "Default",

                url: "{controller}/{action}/{id}",

                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

            );

        }

    }

 

看看我上面标红的代码:这是路由注册,玄机就在这里。那我们去看看MapRoute源码就知道咯:

 

public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) 

        {

            ......

 

            Route route = new Route(url, new MvcRouteHandler())             {

                Defaults = new RouteValueDictionary(defaults),

                Constraints = new RouteValueDictionary(constraints),

                DataTokens = new RouteValueDictionary()

            };

            ......

            return route;

        }

 

看看我们5-8行代码,在MVC应用程序里,在路由注册的时候,我们就已经给他一个默认的HttpRouteHandler对象,就是 New MvcRouteHandler().现在我们反推回去,我们MVC程序在路由注册的时候就已经确定了HttpRouteHandler为MvcRouteHandler,那么当我们在前面PostResolveRequestCache方法里,当我们的请求与路由匹配成功后,自然会返回的是MvcRouteHandler。

 

好啦,MvcRouteHandler生成了。那么MvcRouteHandler能做什么呢?又做了什么呢?

 

再回头看看 PostResolveRequestCache方法,在成功获取到IHttpRouteHandler对象即MvcRouteHandler之后,又做了下面这一个操作:

IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

我们看看这个IHttpHandler 的源码:

 

namespace System.Web.Routing

{  

    public interface IRouteHandler

    {       

        IHttpHandler GetHttpHandler(RequestContext requestContext);

    }

}

 

有一个GetHttpHandler的方法,恰好就调用了这个方法。那我们看看MvcRouteHandler是怎么实现这个GetHttpHandler的呢:

 

public class MvcRouteHandler : IRouteHandler

{

    // Fields

    private IControllerFactory _controllerFactory;

 

    // Methods

    public MvcRouteHandler()

    {

    }

 

    public MvcRouteHandler(IControllerFactory controllerFactory)

    {

        this._controllerFactory = controllerFactory;

    }

 

    protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)

    {

        requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));

        return new MvcHandler(requestContext);

    }

 

    protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)

    {

        string str = (string) requestContext.RouteData.Values["controller"];

        if (string.IsNullOrWhiteSpace(str))

        {

            throw new InvalidOperationException(MvcResources.MvcRouteHandler_RouteValuesHasNoController);

        }

        IControllerFactory factory = this._controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();

        return factory.GetControllerSessionBehavior(requestContext, str);

    }

 

    IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)

    {

        return this.GetHttpHandler(requestContext);

    }

}

 

看第16-20行代码,这时候应该明白了吧。顺理成章的返回了MvcHandler对象。记得我们前面说过,请求最终是被相对应的HttpHander对象处理的。

 

MvcHandler就是那个用来处理Mvc请求的HttpHandler。MvcRouteHandler把请求交给了MvcHandler去做请求处理管道中后续事件的处理操作了。

 

下面我们就看看MvcHandler做了些什么:

MvcHandler                                                           

 

MvcHandler就是最终对request进行处理。

 

MvcHandler的定义如下:

 

 

我们可以看到MvcHandler就是一个普通的Http  Handler.我们知道一个http handler需要实现一个ProcessRequest()的方法,这个方法就是处理request的核心。所以MvcHandler实现了ProcessRequest()方法。

 

ProcessRequest主要功能:

 

(1)在ASP.NET MVC中,会调用MvcHandler的ProcessRequest()方法,此方法会激活具体请求的Controller类对象,触发Action方法,返回ActionResult实例。

 

(2)如果ActionResult是非ViewResult,比如JsonResult, ContentResult,这些内容将直接被输送到Response响应流中,显示给客户端;如果是ViewResult,就会进入下一个渲染视图环节。

 

(3)在渲染视图环节,ViewEngine找到需要被渲染的视图,View被加载成WebViewPage<TModel>类型,并渲染生成Html,最终返回Html。

 

ProcessRequest()定义如下:

 

// Copyright (c) Microsoft Open Technologies, Inc.<pre>// All rights reserved. See License.txt in the project root for license information.

void IHttpHandler.ProcessRequest(HttpContext httpContext) 

{

    ProcessRequest(httpContext);

}

protected virtual void ProcessRequest(HttpContext httpContext) 

{

    HttpContextBase iHttpContext = new HttpContextWrapper(httpContext);

                ProcessRequest(iHttpContext);

}

protected internal virtual void ProcessRequest(HttpContextBase httpContext) {

    SecurityUtil.ProcessInApplicationTrust(() => {

        IController controller;

        IControllerFactory factory;

        ProcessRequestInit(httpContext, out controller, out factory);

    try

    {

        controller.Execute(RequestContext);

    }

    finally

    {

        factory.ReleaseController(controller);

    }

    });

}

 

从上面的代码可以看出调用了一个ProcessRequestInit()方法,定义如下:

 

private void ProcessRequestInit(HttpContextBase httpContext, 

             out IController controller, out IControllerFactory factory) {

    // If request validation has already been enabled, make it lazy.

    // This allows attributes like [HttpPost] (which looks

    // at Request.Form) to work correctly without triggering full validation.

    bool? isRequestValidationEnabled = 

       ValidationUtility.IsValidationEnabled(HttpContext.Current);

    if (isRequestValidationEnabled == true) {

        ValidationUtility.EnableDynamicValidation(HttpContext.Current);

    }

    AddVersionHeader(httpContext);

    RemoveOptionalRoutingParameters();

    // Get the controller type

    string controllerName = RequestContext.RouteData.GetRequiredString("controller");

    // Instantiate the controller and call Execute

    factory = ControllerBuilder.GetControllerFactory();

    controller = factory.CreateController(RequestContext, controllerName);

    if (controller == null) {

        throw new InvalidOperationException(

        String.Format(

            CultureInfo.CurrentCulture,

            MvcResources.ControllerBuilder_FactoryReturnedNull,

            factory.GetType(),

            controllerName));

    }

}

 

在ProcessRequestInit()方法中首先创建了ControllerFactory()的对象 factory.然后ControllerFactory创建了相关Controller的实例.最终调用了Controller的Excute()方法。

 

好我们再来看看ControllerFactory:

 

ControllerFactory           

                                       

主要是用来生成Controller对象

 

ControllerFactory实现了接口IControllerFactory.

 

Controller         

                                                                       

到这里我们大概就知道了,MvcHandler通过ProcessRequest()方法最终创建了Controller对象,这里我们都应该知道,Controller里面包含很多的Action方法,每一次请求至少一个Action方法会被调用。

 

为了明确的实现IController接口,框架里面有一个ControllerBase的类已经实现了IController接口,其实我们自己的Controller也可以不继承ControllerBase,只要实现IController接口即可。

 

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对象实际上使用ActionInvoker来调用Action方法的,当Controller对象被创建后,会执行Controller对象的基类ControllerBase类里面的Excute方法。Excute方法又调用了ExcuteCore()方法。Controller类里面实现了ExcuteCore()方法。ExcuteCore调用了ActionInvoker的InvokerAction方法来调用Action方法。

 

ActionInvoker    

                                                   

ActionInvoker方法有很重要的责任来查找Controller中的Action方法并且调用。

 

 

ActionInvoker是一个实现了IActionInvoker接口的对象:

 

bool InvokeAction(

               ControllerContext controllerContext,

               string actionName

 

Controller类里面暴露了一个ActionInvoker 属性,会返回一个ControllerActionInvoker 。ActionInvoker通过CreateActionInvoker()方法来创建ControllerActionInvoker对象。

 

public IActionInvoker ActionInvoker {

    get {

        if (_actionInvoker == null) {

            _actionInvoker = CreateActionInvoker();

        }

        return _actionInvoker;

    }

    set {

       _actionInvoker = value;

    }

}

   protected virtual IActionInvoker CreateActionInvoker() {

    return new ControllerActionInvoker();

}

 

我们看到CreateActionInvoker()是一个Virtual方法,我们可以实现自己的ActionInvoker.

 

ActionInvoker类需要匹配Controller中详细的Action来执行,而这些详细的信息是由ControllerDescriptor 提供的。ControllerDescriptor 和ActionDescriptor在ActionInvoker中扮演重要的角色。这两个分别是对Controler和Action的详细描述。ControllerDescriptor 描述了Controller的相关信息比如name,action,type等。

 

ActionDescriptor 描述了Action相关的详情,比如name,controller,parameters,attributes和fiflters等。

 

ActionDescriptor 中一个中要的方法就是FindAction(),这个方法返回一个ActionDescriptor 对象,所以ActionInvoker知道该调用哪个Action。

 

 ActionResult           

 

到目前为止,我们看到了Action方法被ActionInvoker调用。所有的Action方法有一个特性,就是返回一个ActionResult类型的数据。

 

public abstract class ActionResult

  {

      public abstract void ExecuteResult(ControllerContext context);

  }

 

ExecuteResult()是一个抽象方法,所以不同的子类可以提供不同的ExecuteResult()实现。

 

ActionResult执行后响应输出到客户端。

 

ViewEngine                 

                                          

ViewResult几乎是大部分应用程序的返回类型,主要通过ViewEngine引擎来展示view的。ViewEngine可能主要就是生成Html元素的引擎。

 

Framwork提供了2种引擎,Razor View Engine 和Web Form View Engine.如果你想自定义引擎,你可以创建一个引擎只要实现IViewEngine接口即可。

 

 

IViewEngine 有下面几个方法:

 

1、FindPartialView :当controller需要返回一个PartialView的时候,FindPartialView方法 就会被调用。

 

2、FindView 

 

3、ReleaseView :主要用来有ViewEngine释放资源

 

ViewResultBase 和ViewResult是比较重要的两个类。ViewResultBase 包含下面的实现代码:

 

if (View == null)

           {

               result = FindView(context); //calls the ViewResult's FindView() method

               View = result.View;

           }

 

           ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);

           View.Render(viewContext, context.HttpContext.Response.Output);

 

protected abstract ViewEngineResult FindView(ControllerContext context); //this is implemented by                                                                        

//the ViewResult

 

protected override ViewEngineResult FindView(ControllerContext context)

    {

        ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);

        if (result.View != null)

        {

            return result;

        }

       //rest of the code omitted 

    }

 

当ViewResult的方法ExecuteResult被调用后,ViewResultBase 的ExecuteResult 方法被调用,然后ViewResultBase 调用ViewResult的FindView 。

紧接着ViewResult 返回ViewEngineResult,之后ViewEngineResult调用Render()方法来绘制html输出响应。

 

总结:如果我们理解了整个过程中发生了什么,哪些类和哪些方法被调用,我们就可以在需要扩展的地方轻松的进行扩展。

posted on 2016-07-21 12:47  張暁磊  阅读(219)  评论(0编辑  收藏  举报