概述
本 文主要分析Orchard項目的Global.asax文件,而真正的分析入口點在Global.asax的CodeBehind文件 Global.asax.cs中,即Orchard.Web.MvcApplication類(以下簡稱MvcApplication類)。
下面轉入Starter<T>類看其構造函數的定義:
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)
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多行代碼,而且包括注釋。但留給我們的疑問倒卻不少:
對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是如何工作的?
5、Orchard.WarmupStarter程序集是做什么用的?
6、Starter<T>在把任務傳回MvcApplication之前,完成了那些工作?
7、MvcApplication.MvcSingletons方法涉及到IoC/DI,Autofac是如何工作的?
相關類型:
Orchard.WarmupStarter.Starter<T>
Orchard.WarmupStarter.Starter<T>
Orchard.Environment.DefaultOrchardHost : Orchard.Environment.IOrchartHost
Orchard.Environment.OrchardStarter
參考資料: