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"的事件還不明確,這里暫且這么簡單的理解。
根 據約定,這三個事件分別對應Application_Start、Application_BeginRequest和 Application_EndRequest事件處理程序(方法),當然也可以通過重寫HttpApplication的Init方法注冊其他名稱的事 件處理程序——Application_Start除外。
Start是個特殊事件,僅在請求 ASP.NET 應用程序中第一個資源(如aspx頁)時調用。在該事件的處理程序(Application_Start方法)中,可用於也應該僅用於在應用程序啟動期間設置靜態共享數據。Orchard中主要用於配置Autofac容器、安裝擴展(Modules和Themes統稱為擴展)、創建並激活Shell(子站點)。
BeginRequest事件在 ASP.NET 響應請求時作為 HTTP 執行管線鏈(管道)中的第一個事件發生。Orchard中主要用戶監視擴展;如果擴展發生改變會重新安裝擴展、重新創建並激活Shell;如果Shell狀態等也發生改變會重新激活Shell。
EndRequest事件在 ASP.NET 響應請求時作為 HTTP 執行管線鏈中的最后一個事件發生。Orchard中主要用於處理完"處理引擎(ProcessingEngine)"中的任務(Task)。
一、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,調用Starter<T>類帶三個委托參數的構造函數創建其實例並賦給了靜態私有字段_starter:
    _starter =  new  Starter < IOrchardHost  >(HostInitialization, HostBeginRequest, HostEndRequest);
其中靜態私有字段_starter定義在MvcApplication類中有定義:
    private  static  Starter <  IOrchardHost > _starter;
另暫且不管IOrchardHost的定義及其作用,這里只需要知道Starter<T>類有責任創建一個IOrchardHost(DefaultOrchardHost)實例。
Starter<T> 類構造函數接受三個委托參數。在創建該類型的對象時,傳入HstInitialization、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這幾個方法的作用。
二、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)中。

從 上面不難看出,一項交由MvcApplication來完成的工作,它推給了Starter<T>,后者完成一部分后又轉給 MvcApplication處理,MvcApplication接着處理一部分后,把剩下的工作全交給 IOrchardHost(DefaultOrchardHost)來完成。

在分析Orchard.WarmupStarter程序集的時候將詳細分析Starter<T>類。對IOrchardHost(DefaultOrchardHost)也有專門的篇幅來分析。
三、疑問
對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>在把任務傳回MvcApplication之前,完成了那些工作?
7、
MvcApplication.MvcSingletons方法涉及到IoC/DI,Autofac是如何工作的?

相關類型:
Orchard.WarmupStarter.Starter<T>
Orchard.Environment.DefaultOrchardHost : Orchard.Environment.IOrchartHost
Orchard.Environment.OrchardStarter

參考資料:
HttpApplication的認識與加深理解



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM