標籤:struct 成功 prot 身份認證 3.0.0 name code 重寫 工作
以IIS 6.0為例,在背景工作處理序w3wp.exe中,利用Aspnet_ispai.dll載入.NET運行時(如果.NET運行時尚未載入)。IIS 6引入了應用程式集區的概念,一個背景工作處理序對應著一個應用程式集區。一個應用程式集區可以承載一個或者多個Web應用,每個Web應用映射到一個IIS虛擬目錄。與IIS 5.x一樣,每一個Web應用運行在各自的應用程式定義域中。
如果HTTP.SYS接收到的HTTP請求是對該Web應用的第一次訪問,當成功載入了運行時後,會通過AppDomainFactory為該Web應用建立一個應用程式定義域(AppDomain)。隨後,一個特殊的運行時IsapiRuntime被載入。IsapiRuntime定義在程式集System.Web中,對應的命名空間為System.Web.Hosting。IsapiRuntime會接管該HTTP請求。
IsapiRuntime會首先建立一個IsapiWorkerRequest對象,用於封裝當前的HTTP請求,並將該IsapiWorkerRequest對象傳遞給ASP.NET運行時:HttpRuntime,從此時起,HTTP請求正式進入了ASP.NET管道。根據IsapiWorkerRequest對象,HttpRuntime會建立用於表示當前HTTP請求的上下文(Context)對象:HttpContext。
隨著HttpContext被成功建立,HttpRuntime會利用HttpApplicationFactory建立新的或者擷取現有的HttpApplication對象。實際上,ASP.NET維護著一個HttpApplication對象池,HttpApplicationFactory從池中選取可用的HttpApplication使用者處理HTTP請求,處理完畢後將其釋放到對象池中。HttpApplicationFactory負責處理當前的HTTP請求。
在HttpApplication初始化過程中,會根據設定檔載入並初始化相應的HttpModule對象。對於HttpApplication來說,在它處理HTTP請求的不同的階段會觸發不同的事件(Event),而HttpModule的意義在於通過註冊HttpApplication的相應的事件,將所需的操作注入整個HTTP請求的處理流程。ASP.NET的很多功能,比如身分識別驗證、授權、緩衝等,都是通過相應的HttpModule實現的。
而最終完成對HTTP請求的處理實現在另一個重要的對象中:HttpHandler。對於不同的資源類型,具有不同的HttpHandler。比如.aspx頁對應的HttpHandler為System.Web.UI.Page,WCF的.svc檔案對應的HttpHandler為System.ServiceModel.Activation.HttpHandler。上面整個處理流程如圖7所示。
圖7 ASP.NET 處理管道
HttpApplication
HttpApplication是整個ASP.NET基礎架構的核心,它負責處理分發給它的HTTP請求。由於一個HttpApplication對象在某個時刻只能處理一個請求,只有完成對某個請求的處理後,HttpApplication才能用於後續的請求的處理。所以,ASP.NET採用對象池的機制來建立或者擷取HttpApplication對象。具體來講,當第一個請求抵達的時候,ASP.NET會一次建立多個HttpApplication對象,並將其置於池中,選擇其中一個對象來處理該請求。當處理完畢,HttpApplication不會被回收,而是釋放到池中。對於後續的請求,閒置HttpApplication對象會從池中取出,如果池中所有的HttpApplication對象都處於繁忙的狀態,ASP.NET會建立新的HttpApplication對象。
HttpApplication處理請求的整個生命週期是一個相對複雜的過程,在該過程的不同階段會觸發相應的事件。我們可以註冊相應的事件,將我們的處理邏輯注入到HttpApplication處理請求的某個階段。我們接下來介紹的HttpModule就是通過HttpApplication事件註冊的機制實現相應的功能的。表1按照實現的先後順利列出了HttpApplication在處理每一個請求時觸發的事件名稱。
表1
名稱 |
描述 |
BeginRequest |
HTTP管道開始處理請求時,會觸發BeginRequest事件 |
AuthenticateRequest,PostAuthenticateRequest |
ASP.NET先後觸發這兩個事件,使安全模組對請求進行身分識別驗證 |
AuthorizeRequest,PostAuthorizeRequest |
ASP.NET先後觸發這兩個事件,使安全模組對請求進程授權 |
ResolveRequestCache,PostResolveRequestCache |
ASP.NET先後觸發這兩個事件,以使緩衝模組利用緩衝的直接對請求直接進程響應(緩衝模組可以將響應內容進程緩衝,對於後續的請求,直接將緩衝的內容返回,從而提高響應能力)。 |
PostMapRequestHandler |
對於訪問不同的資源類型,ASP.NET具有不同的HttpHandler對其進程處理。對於每個請求,ASP.NET會通過副檔名選擇匹配相應的HttpHandler類型,成功匹配後,該實現被觸發 |
AcquireRequestState,PostAcquireRequestState |
ASP.NET先後觸發這兩個事件,使狀態管理模組擷取基於當前請求相應的狀態,比如SessionState |
PreRequestHandlerExecute,PostRequestHandlerExecute |
ASP.NET最終通過一請求資源類型相對應的HttpHandler實現對請求的處理,在實行HttpHandler前後,這兩個實現被先後觸發 |
ReleaseRequestState,PostReleaseRequestState |
ASP.NET先後觸發這兩個事件,使狀態管理模組釋放基於當前請求相應的狀態 |
UpdateRequestCache,PostUpdateRequestCache |
ASP.NET先後觸發這兩個事件,以使緩衝模組將HttpHandler處理請求得到的相應儲存到輸出緩衝中 |
LogRequest,PostLogRequest |
ASP.NET先後觸發這兩個事件為當前請求進程日誌記錄 |
EndRequest |
整個請求處理完成後,EndRequest事件被觸發 |
對於一個ASP.NET應用來說,HttpApplication派生於global.asax檔案,我們可以通過建立global.asax檔案對HttpApplication的請求處理行為進行定製。global.asax採用一種很直接的方式實現了這樣的功能,這種方式既不是我們常用的方法重寫(Method Overriding)或者事件註冊,而是直接採用方法名匹配。在global.asax中,我們按照這樣的方法命名規則進行事件註冊:Application_{Event Name}。比如Application_BeginRequest方法用於處理HttpApplication的BeginRequest事件。如果通過VS建立一個global.asax檔案,下面是預設的定義。
1: <%@ Application Language="C#" %>
2: <script runat="server">
3: void Application_Start(object sender, EventArgs e) {}
4: void Application_End(object sender, EventArgs e) {}
5: void Application_Error(object sender, EventArgs e) {}
6: void Session_Start(object sender, EventArgs e) {}
7: void Session_End(object sender, EventArgs e) {}
8: </script>
HttpModule
ASP.NET為建立各種.NET Web應用提供了強大的平台,它擁有一個具有高度可擴充性的引擎,並且能夠處理對於不同資源類型的請求。那麼,是什麼成就了ASP.NET的高可擴充性呢? HttpModule功不可沒。
從功能上講,HttpModule之於ASP.NET,就好比ISAPI Filter之於IIS一樣。IIS將接收到的請求分發給相應的ISAPI Extension之前,註冊的ISAPI Filter會先截獲該請求。ISAPI Filter可以擷取甚至修改請求的內容,完成一些額外的功能。與之相似地,當請求轉入ASP.NET管道後,最終負責處理該請求的是與請求資源類型相匹配的HttpHandler對象,但是在Handler正式工作之前,ASP.NET會先載入並初始化所有配置的HttpModule對象。HttpModule在初始化的過程中,會將一些功能註冊到HttpApplication相應的事件中,那麼在HttpApplication整個請求處理生命週期中的某個階段,相應的事件會被觸發,通過HttpModule註冊的事件處理常式也得以執行。
所有的HttpModule都實現了IHttpModule介面,下面是IHttpModule的定義。其中Init方法用於實現HttpModule自身的初始化,該方法接受一個HttpApplication對象,有了這個對象,事件註冊就很容易了。
1: public interface IHttpModule
2: {
3: void Dispose();
4: void Init(HttpApplication context);
5: }
ASP.NET提供的很多基礎構件(Infrastructure)功能都是通過相應的HttpModule實現的,下面類列出了一些典型的HttpModule:
- OutputCacheModule:實現了輸出緩衝(Output Caching)的功能;
- SessionStateModule:在無狀態的HTTP協議上實現了基於會話(Session)的狀態;
- WindowsAuthenticationModule + FormsAuthenticationModule + PassportAuthentication- Module:實現了3種典型的身份認證方式:Windows認證、Forms認證和Passport認證;
- UrlAuthorizationModule + FileAuthorizationModule:實現了基於Uri和檔案ACL(Access Control List)的授權。
而另外一個重要的HttpModule與WCF相關,那麼就是System.ServiceModel. Activation.HttpModule。HttpModule定義在System.ServiceModel程式集中,在預設的情況下,HttpModule完成了基於IIS的寄宿工作。
除了這些系統定義的HttpModule之外,我們還可以自訂HttpMoudle。通過Web.config,我們可以很容易地將其註冊到我們的Web應用中。
HttpHandler
如果說HttpModule相當於IIS的ISAPI Filter的話,我們可以說HttpHandler則相當於IIS的ISAPI Extension,HttpHandler在ASP.NET中扮演請求的最終處理者的角色。對於不同資源類型的請求,ASP.NET會載入不同的Handler來處理,也就是說.aspx page與.asmx web service對應的Handler是不同的。
所有的HttpHandler都實現了介面IHttpHandler。下面是IHttpHandler的定義,方法ProcessRequest提供了處理請求的實現。
1: public interface IHttpHandler
2: {
3: void ProcessRequest(HttpContext context);
4: bool IsReusable { get; }
5: }
對於某些HttpHandler,具有一個與之相關的HttpHandlerFactory,用於建立或者擷取相應的HttpHandler。HttpHandlerFactory實現介面IHttpHandlerFactory,方法GetHandler用於建立新的HttpHandler,或者擷取已經存在的HttpHandler。
1: public interface IHttpHandlerFactory
2: {
3: IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);
4: void ReleaseHandler(IHttpHandler handler);
5: }
HttpHandler和HttpHandlerFactory的類型都可以通過相同的方式配置到Web.config中。下面一段配置包含對3種典型的資源類型的HttpHandler配置:.aspx,.asmx和.svc。可以看到基於WCF Service的HttpHandler類型為:System.ServiceModel.Activation.HttpHandler。
1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <system.web>
4: <httpHandlers>
5: <add path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
6: <add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>
7: <add path="*.asmx" verb="*" type="System.Web.Services.Protocols.WebServiceHandlerFactory, System.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" validate="False"/>
8: </httpHandlers>
9: </system.web>
10: </configuration>
ASP.NET管道