请注意,本站并不支持低于IE8的浏览器,为了获得最佳效果,请下载最新的浏览器,推荐下载 Chrome浏览器
欢迎光临。交流群:166852192

Orchard源码分析(2):Orchard.Web.MvcApplication类(Global)


概述

分析一个的ASP.NET项目源码,首先可以浏览其项目结构,了解项目之间的依赖关系,可以大致一窥项目的全貌。其次可以浏览Web.configGlobal.asax文件,可以找到应用程序的入口。
本文主要分析Orchard项目的Global.asax文件,而真正的分析入口点在Global.asax的CodeBehind文件Global.asax.cs中,即Orchard.Web.MvcApplication类(以下简称MvcApplication类)。


MvcApplication类处理了三个事件Start,BeginRequest和EndRequest。其中是否真有名为Start的事件还不明确,这里暂且这么简单的理解。
Start是个特殊事件,仅在请求 ASP.NET 应用程序中第一个资源(如aspx页)时调用。在该事件处理程序(方法)中,可用于也应该仅用于为应用程序启动期间设置静态共享数据。
BeginRequest事件在 ASP.NET 响应请求时作为 HTTP 执行管线链(管道)中的第一个事件发生。

EndRequest事件在 ASP.NET 响应请求时作为 HTTP 执行管线链中的最后一个事件发生。


根据约定,这三个事件分别对应Application_Start、Application_BeginRequest和Application_EndRequest事件处理程序(方法),当然也可以通过重写HttpApplication的Init方法注册其他名称的事件处理程序——Application_Start除外。

一、Application_Start方法

下面的代码分析要在MvcApplication类和Orchard.WarmupStarter.Starter<T>类(以下简称Starter<T>类)之前切换。
Application_Start方法首先调用了RegisterRoutes方法,添加了一个路由配置,将对后缀为.axd的请求排除在ASP.NET MVC处理管道之外。这里将方法内联后看:
    RouteTable.Routes.IgnoreRoute({resource}.axd/{*pathInfo} );
接着Application_Start方法中使用泛型类型参数IOrchardHost,调用Orchard.WarmupStarter.Starter<T>类(以下简称Starter<T>类)带三个委托参数的构造函数创建其实例并赋给了静态私有字段_starter:
    _starter = new Starter<IOrchardHost >(HostInitialization, HostBeginRequest, HostEndRequest);
其中静态私有字段_starter定义在MvcApplication类中有定义:
    private static Starter< IOrchardHost> _starter;
另暂且不管IOrchardHost的定义及其作用,只需要知道Starter<T>类有责任创建一个IOrchardHost(DefaultOrchardHost)实例。
Starter<T>类构造函数使用的HostInitialization、HostBeginRequest和HostEndRequest是在MvcApplication类中定义的三个私有静态方法:
    IOrchardHost HostInitialization(HttpApplication application)
    void HostBeginRequest(HttpApplication application, IOrchardHost host)
    void HostEndRequest(HttpApplication application, IOrchardHost host)
下面转入Starter<T>类型看该构造函数的定义:

         public Starter(Func <HttpApplication, T> initialization, Action<HttpApplication , T> beginRequest, Action<HttpApplication , T> endRequest) {
            _initialization = initialization;
            _beginRequest = beginRequest;
            _endRequest = endRequest;
            }
 
可见该构造函数内部只是简单的赋值操作,将参数值赋给Starter<T>类内部对应的私有字段。
再转入Application_Start方法继续分析。
Application_Start方法接着调用_starter的OnApplicationStart方法,将当前的MvcHttpApplication实例作为参数传入:
    _starter.OnApplicationStart( this);
深入Starter<T>.OnApplicationStart方法内部,该方法通过线程池启动一个线程,最终会调用MvcHttpApplication类中的HostInitialization方法,即作为参数传给Starter<T>构造函数的委托所包装的方法。具体分析请参考下一篇关于Orchard.WarmupStarter程序集的分析。这里再看看HostInitialization方法的定义:        
    private static IOrchardHost HostInitialization( HttpApplication application) {
        var host = OrchardStarter .CreateHost(MvcSingletons);


        host.Initialize();


        // initialize shells to speed up the first dynamic query
        host.BeginRequest();
        host.EndRequest();


         return host;
    }
该方法目的是创建一个IOrchardHost(DefaultOrchardHost)对象并调用其几个方法,然后将其返回。这里暂不深究IOrchardHost这几个方法的作用。


从上面的分析,看起来Starter<T>类是个懒惰的类,几乎没做什么事。虽然叫了让它工作,它却又甩回来让MvcHttpApplication来做了&mdash;&mdash;实际上并不完全是这样。在分析Orchard.WarmupStarter程序集的时候将详细分析Starter<T>类。


二、Application_BeginRequest方法和Application_EndRequest方法
这两个方法比较简单,只是简单调用Starter<T>类的对应方法:

     protected void Application_BeginRequest() {
        _starter.OnBeginRequest( this);
    }


    protected void Application_EndRequest() {
        _starter.OnEndRequest( this);
    }
Starter<T>的OnBeginRequest和OnEndRequest方法会调用MvcApplication的HostBeginRequest和HostEndRequest方法:
    public void OnBeginRequest(HttpApplication application)
    {
        // ... (省略的代码请查看Starter<T>类,在下一篇中将会进行分析)
        // Only notify if the initialization has successfully completed
        if (_initializationResult != null )
        {
            _beginRequest(application, _initializationResult);
        }
    }


    public void OnEndRequest(HttpApplication application)
    {
        // Only notify if the initialization has successfully completed
        if (_initializationResult != null )
        {
            _endRequest(application, _initializationResult);
        }
    }
HostBeginRequest和HostEndRequest方法最终会转到对IOrchardHost(DefaultOrchardHost)对应方法的调用:

    private static void HostBeginRequest( HttpApplication application, IOrchardHost host) {
        application.Context.Items[ originalHttpContext] = application.Context;
        host.BeginRequest();
    }


    private static void HostEndRequest( HttpApplication application, IOrchardHost host) {
        host.EndRequest();
    }
注意,HostBeginRequest方法将当前请求上下文(HttpContext)保存在会话状态(HttpContext.Items)中。


三、疑问
对MvcHttpApplication分析暂时就到这里,它虽然就短短60多行代码,而且包括注释。但留给我们的疑问倒却不少:

1、上面虽然数次提到IOrchardHost(DefaultOrchardHost),但它到底是什么,它的作用又是什么?

2、MvcApplication.HostInitialization方法中,调用OrchardStarter.CreateHost方法创建IOrchardHost实例的,它是如何创建的?
3、MvcApplication.HostInitialization方法中,调用IOrchardHost.Initialize方法后,为什么还要调用IOrchardHost.BeginRequest和IOrchardHost.EndRequest方法?
4、为什么要在MvcApplication.HostBeginRequest方法中将当前请求上下文(HttpContext)保存在会话状态(HttpContext.Items)中?
5、Orchard.WarmupStarter程序集是做什么用的?
6、Starter<T>在&ldquo;中转&rdquo;处理的时候,是否做过什么额外的工作?
7、MvcSingletons涉及到IoC/DI,Autofac是如何工作的?



相关类型:
Orchard.WarmupStarter.Starter<T>

Orchard.Environment.DefaultOrchardHost : Orchard.Environment.IOrchartHost
Orchard.Environment.OrchardStarter


参考资料:
Global.asax详解
再谈IIS与ASP.NET管道
ASP.NET 编译概述
IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述
IIS 7 的 ASP.NET 应用程序生命周期概述

作者原创内容不容易,如果觉得内容不错,请点击右侧“打赏”,赏俩给作者花花,也算是对作者付出的肯定,也可以鼓励作者原创更多更好内容。
更多详情欢迎到QQ群 166852192 交流。