【转】Asp.net的生命周期之应用程序生命周期
參考:http://msdn.microsoft.com/zh-cn/library/ms178473(v=vs.100).aspx
參考:http://www.cnblogs.com/JimmyZhang/archive/2007/09/04/880967.html
Http請求剛剛到達(dá)服務(wù)器的時候
當(dāng)服務(wù)器接收到一個 Http請求的時候,IIS (Internet Information Services,互聯(lián)網(wǎng)信息服務(wù))首先需要決定如何去處理這個請求。
什么是IIS?
IIS是一種Web(網(wǎng)頁)服務(wù)組件,(其中包括Web服務(wù)器、FTP服務(wù)器、NNTP服務(wù)器和SMTP服務(wù)器,分別用于網(wǎng)頁瀏覽、文件傳輸、新聞服務(wù)和郵件發(fā)送等方面,它使得在網(wǎng)絡(luò)(包括互聯(lián)網(wǎng)和局域網(wǎng))上發(fā)布信息成了一件很容易的事。對于IIS來說,它依賴一個叫做 HTTP.SYS 的內(nèi)置驅(qū)動程序來監(jiān)聽來自外部的 HTTP請求。IIS支持的東西也比較多,最常見的就是處理多媒體的功能(例如:為什么請求的圖片會被顯示在客戶端?就是IIS進(jìn)行處理的。這也是為什么要防圖片盜鏈:若圖片被盜鏈,在其它網(wǎng)站打開本站圖片同樣占一個iis,而你的IIS資源是有限的),當(dāng)然如果你進(jìn)行了設(shè)置,圖片的處理也能交由應(yīng)用程序進(jìn)行處理。?
在操作系統(tǒng)啟動的時候,IIS首先在HTTP.SYS中注冊自己的虛擬路徑(實際上相當(dāng)于告訴HTTP.SYS哪些URL是可以訪問的,這也是為什么你訪問不存在的文件會出現(xiàn) 404 錯誤),如果請求的是一個可訪問的URL,HTTP.SYS會將這個請求交給 IIS 工作者進(jìn)程。
?
注:一會要說的aspnet_isapi.exe,在IIS6.0中叫做 w3wp.exe,IIS5.0中叫做 aspnet_wp.exe。
那IIS是怎么識別這些Asp、Java、VBscript、Asp.Net等程序發(fā)布的頁面,依據(jù)的是什么呢?
答:根據(jù)文件的后綴名。
服務(wù)器獲取所請求的頁面(也可以是多媒體、文件(也有后綴名)等)的后綴名以后,接下來會在服務(wù)器端尋找可以處理這類后綴名的應(yīng)用程序。IIS不可能處理各種后綴名的應(yīng)用程序,要處理這些,就要借助 ISAPI 應(yīng)用程序(NOTE:Internet Server Application Programe Interface,互聯(lián)網(wǎng)服務(wù)器應(yīng)用程序接口)。ISAPI實際上只是一個接口,起到一個代理的作用,它的主要工作是映射所請求的頁面(文件)? 和與此后綴名相對應(yīng)的實際的處理程序。
除了映射文件與其對應(yīng)的處理程序以外,ISAPI 還需要做一些其他的工作:
讓我們更進(jìn)一步地看一下 ISAPI ,看看它到底是什么樣子,請按下面的步驟進(jìn)行:
你應(yīng)該會看到如下的畫面:
圖1. 應(yīng)用程序配置
很清楚地就可以看到,所有IIS所能處理,或者叫?ISAPI 所提供代理服務(wù)的 文件類型 及其相對應(yīng)的實際的后臺處理程序都在這里清楚地列出來了。
我們找到 .aspx 的應(yīng)用處理程序,然后點(diǎn)“編輯”,會出現(xiàn)下面的畫面:
圖2. 編輯.aspx文件的處理程序
可以看出,所有的.aspx文件實際上都是由 aspnet_isapi.dll 。這個程序來處理的,當(dāng)IIS把對于.aspx頁面的請求提通過ISAPI交給了aspnet_isapi.dll以后,接著就是只是等待結(jié)果,返回給用戶(實際是IIS 接收返回的數(shù)據(jù)流,并重新返還給 HTTP.SYS,最后,HTTP.SYS 再將這些數(shù)據(jù)返回給客戶端瀏覽器。)。現(xiàn)在我們應(yīng)該知道:Asp.Net 只是服務(wù)器(IIS)的一個組成部分而已,它是一個 ISAPI擴(kuò)展。
Ps:到這里我們就應(yīng)該大致知道,一個請求到服務(wù)器后,這個請求是怎么樣被處理的(至于怎么到的,那是網(wǎng)絡(luò)傳輸中的事)。我們還要知道一個內(nèi)容(可能有點(diǎn)多余),我們開發(fā)的網(wǎng)站是部署在服務(wù)端的,這個網(wǎng)頁是輸入網(wǎng)址就能直接看的,這些程序是經(jīng)過發(fā)布的。這多少和你本地運(yùn)行程序有點(diǎn)類似)。
應(yīng)用程序生命周期前:編譯
?
在第一次對應(yīng)用程序發(fā)出請求時,ASP.NET 按特定順序編譯應(yīng)用程序項。?要編譯的第一批項稱為頂級項。?在第一次請求之后,僅當(dāng)依賴項更改時才會重新編譯頂級項。?下表描述編譯 ASP.NET 頂級項的順序。
?
| 項 | 說明 |
| App_GlobalResources | 編譯應(yīng)用程序的全局資源并生成資源程序集。?應(yīng)用程序的 Bin 文件夾中的任何程序集都鏈接到資源程序集。 |
| App_WebResources | 創(chuàng)建并編譯 Web 服務(wù)的代理類型。?所生成的 Web 引用程序集將鏈接到資源程序集(如存在)。 |
| Web.config 文件中定義的配置文件屬性 | 如果應(yīng)用程序的 Web.config 文件中定義了配置文件屬性,則生成一個包含配置文件對象的程序集。 |
| App_Code | 生成源代碼文件并創(chuàng)建一個或更多個程序集。?所有代碼程序集和配置文件程序集都鏈接到資源和 Web 引用程序集(如果有)。 |
| Global.asax | 編譯應(yīng)用程序?qū)ο蟛⑵滏溄拥剿邢惹爱a(chǎn)生的程序集。 |
?
在編譯應(yīng)用程序的頂級項之后,ASP.NET 將根據(jù)需要編譯文件夾、頁和其他項。?下表描述編譯 ASP.NET 文件夾和項的順序。?
?
| 項 | 說明 |
| App_LocalResources | 如果包含被請求項的文件夾包含 App_LocalResources 文件夾,則編譯本地資源文件夾的內(nèi)容并將其鏈接到全局資源程序集。 |
| 各個網(wǎng)頁(.aspx 文件)、用戶控件(.ascx 文件)、HTTP 處理程序(.ashx 文件)和 HTTP 模塊(.asmx 文件) | 根據(jù)需要編譯并鏈接到本地資源程序集和頂級程序集。 |
| 主題、主控頁、其他源文件 | 在編譯引用頁時編譯那些頁所引用的各個主題、主控頁和其他源代碼文件的外觀文件。 |
?
由于應(yīng)用程序在第一次請求時進(jìn)行編譯,所以對應(yīng)用程序的初始請求所花的時間會明顯長于后續(xù)請求。?可以預(yù)編譯應(yīng)用程序以減少第一次請求所需的時間。編譯后的程序集緩存在服務(wù)器上并在后續(xù)請求時被重用,并且只要源代碼未更改,就會在應(yīng)用程序重新啟動之間得到保留。?
上面的是MSDN中的,咱說點(diǎn)別的:在編譯時,.aspx其實是屬于前臺頁面,當(dāng)然也可以在前臺寫C#代碼,這只和選的編程模式有關(guān)。執(zhí)行的程序都是被編譯了的,簡單的說,就是頁面是沒法子運(yùn)行的,只有編譯后才能執(zhí)行。.aspx編譯后是前臺繼承與后臺。后臺的頁碼編譯成程序集,而前臺代碼是根據(jù)的選擇模式有關(guān)。網(wǎng)站將前臺頁面 直接以前臺頁面類的方式 編譯到程序集里;網(wǎng)站應(yīng)用程序,只能編譯 后臺頁面類到程序集,前臺頁面必須在被訪問的時候 才編譯到程序集中。當(dāng)然.aspx頁面有三種控件,分別是Html標(biāo)簽、Html服務(wù)器控件、服務(wù)器控件三種,這些控件會被編譯成不同的類,他們的簡潔性是由低到復(fù)雜的(此處有空再整下三種控件的區(qū)別)。
?
應(yīng)用程序生命周期概述
說這么多也沒說到應(yīng)用程序的生命生命周期。程序的生命周期也是有幾種的,有應(yīng)用程序生命周期、Asp.Net頁生命周期、控件生命周期等。
參考MSDN地址:
http://msdn.microsoft.com/zh-cn/library/ms178473(v=vs.100).aspx?? 這是IIS5和IIS6的
http://msdn.microsoft.com/zh-cn/library/bb470252(v=vs.100).aspx?? ?這是IIS7的
我們注意:
在 IIS 6.0 中,有兩個請求處理管道。 一個管道用于本機(jī)代碼 ISAPI 篩選器和擴(kuò)展組件。 另一個管道用于托管代碼應(yīng)用程序組件,如 ASP.NET。
在 IIS 7.0 中,ASP.NET 運(yùn)行時與 Web 服務(wù)器集成,這樣就有了一個針對所有請求的統(tǒng)一的請求處理管道。
我的梳理是以IIS5和IIS6為基本,畢竟程序是向下兼容的。以下文字大部分是MSDN的東西,有些圖是自己找的。
1.用戶從Web服務(wù)器請求應(yīng)用程序
ASP.NET 應(yīng)用程序的生命周期以瀏覽器向 Web 服務(wù)器(對于 ASP.NET 應(yīng)用程序,通常為 IIS)發(fā)送請求為起點(diǎn)。?ASP.NET 是 Web 服務(wù)器下的 ISAPI 擴(kuò)展。?Web 服務(wù)器接收到請求時,會對所請求的文件的文件擴(kuò)展名進(jìn)行檢查,確定應(yīng)由哪個 ISAPI 擴(kuò)展處理該請求,然后將該請求傳遞給合適的 ISAPI 擴(kuò)展。?ASP.NET 處理已映射到其上的文件擴(kuò)展名,如 .aspx、.ascx、.ashx 和 .asmx。
如果文件擴(kuò)展名尚未映射到 ASP.NET,則 ASP.NET 將不會接收該請求。例如,由于 .htm 文件通常沒有映射到 ASP.NET,因此 ASP.NET 將不會對 .htm 文件請求執(zhí)行身份驗證或授權(quán)檢查。因此,即使文件僅包含靜態(tài)內(nèi)容(包括Javascript文件、圖片、CSS文件等等),如果希望 ASP.NET 檢查身份驗證,也應(yīng)使用映射到 ASP.NET 的文件擴(kuò)展名創(chuàng)建該文件。如果要創(chuàng)建服務(wù)于特定文件擴(kuò)展名的自定義處理程序,必須在 IIS 中將該擴(kuò)展名映射到 ASP.NET,還必須在應(yīng)用程序的 Web.config 文件中注冊該處理程序(常見的是IhttpModule進(jìn)行擴(kuò)展,可參考:http://msdn.microsoft.com/zh-cn/library/bb398986%28v=vs.100%29.aspx)。不建議這些交由Asp.Net處理,畢竟資源有限。
先看一張MSDN提供的用戶請求.aspx、.ascx、.ashx 和 .asmx等文件的處理過程吧。
?
2.ASP.NET 接收對應(yīng)用程序的第一個請求
當(dāng)用戶請求的文件的后綴名為:?.aspx、.ascx、.ashx 和 .asmx時,IIS會把這個請求交由ISAPI ,ISAP找到aspnet_ISAPI,然后讓aspnet_ISAPI進(jìn)行處理。
當(dāng) ASP.NET?接收到對應(yīng)用程序中任何資源的第一個請求時,名為 ApplicationManager?的類會創(chuàng)建一個應(yīng)用程序域(AppDomanin)。?應(yīng)用程序域為全局變量提供應(yīng)用程序隔離,并允許單獨(dú)卸載每個應(yīng)用程序。?在應(yīng)用程序域中,將為名為 HostingEnvironment 的類創(chuàng)建一個實例,該實例提供對有關(guān)應(yīng)用程序的信息(如存儲該應(yīng)用程序的文件夾的名稱)的訪問。
看不懂沒關(guān)系想來看下他們分別是干什么的:
ApplicationManager?對象在 ASP.NET 應(yīng)用程序的宿主環(huán)境中提供對象生存期管理。也就是為?ASP.NET 宿主應(yīng)用程序管理?ASP.NET 應(yīng)用程序域。?該對象負(fù)責(zé):
- 激活和初始化 ASP.NET 應(yīng)用程序;
- 管理應(yīng)用程序生存期和在應(yīng)用程序中注冊的對象的生存期;
- 公開宿主環(huán)境使用的對象以處理 ASP.NET 應(yīng)用程序請求;
- 提供任意給定時刻運(yùn)行于宿主進(jìn)程中的應(yīng)用程序的列表;
再看下應(yīng)用程序域是干啥的:為全局變量提供應(yīng)用程序隔離,并允許單獨(dú)卸載每個應(yīng)用程序。這時再看看上面的那張圖(PS:想成此時只有一次請求),不難理解:要進(jìn)行管理還得需要一個第三方來對宿主對象和ApplicationManager之間進(jìn)行信息交流,且這個第三方還得在在應(yīng)用程序域中,而這第三方就是HostingEnvironment。
HostingEnvironment的作用是什么呢?在托管應(yīng)用程序的應(yīng)用程序域內(nèi)向托管應(yīng)用程序提供應(yīng)用程序管理功能和應(yīng)用程序服務(wù)。備注:每個托管應(yīng)用程序域都包含?HostingEnvironment?類的一個靜態(tài)實例,該實例提供對應(yīng)用程序管理功能和應(yīng)用程序服務(wù)的訪問。
這只是接到請求的第一步處理,也就是為后續(xù)處理提供必要的環(huán)境。不得不說,在IIS 6引入了Application Pool的概念,其實就是一個application的容器,但這個容器我們可以創(chuàng)建若干個。一個請求對應(yīng)一個Application,而一個Application對應(yīng)一個Worker Process:w3wp.exe,在Worker Process中才開始真正的處理,處理的過程就是在Application的管線中。對運(yùn)行Asp.Net的進(jìn)程來說,進(jìn)程內(nèi)的資源畢竟有限,用戶第一次在應(yīng)用程序中請求 ASP.NET 頁或進(jìn)程時,將創(chuàng)建?HttpApplication?的一個新實例,再次請求時為了盡可能提高性能,進(jìn)程就要對多個請求進(jìn)行重復(fù)使用這個HttpApplication?實例。?
只要知道HostingEnviroment即可,下面先簡單說下大致的流程:在初始化的時候,加載ASP.NET?ISAPI,ASP.NET?ISAPI進(jìn)而加載CLR。ASP.NET ISAPI會創(chuàng)建一個叫做aspnet_wp.exe的Worker Process(如果該進(jìn)程不存在的話),在aspnet_wp.exe初始化的時候會加載CLR,從而為ASP.NET Application創(chuàng)建一個托管的運(yùn)行環(huán)境, 在CLR初始化的使用會加載兩個重要的dll:AppManagerAppDomainFactory和ISAPIRuntime。通過 AppManagerAppDomainFactory的Create方法為Application創(chuàng)建一個Application Domain;通過ISAPIRuntime的ProcessRequest處理Request,進(jìn)而將流程拖入到ASP.NET Http Runtime Pipeline。???
?
如下圖:
?
圖注:為了避免用戶應(yīng)用程序訪問或者修改關(guān)鍵的操作系統(tǒng)數(shù)據(jù),windows提供了兩種處理器訪問模式:用戶模式(User Mode)和內(nèi)核模式(Kernel Mode)。一般地,用戶程序運(yùn)行在User mode下,而操作系統(tǒng)代碼運(yùn)行在Kernel Mode下。Kernel Mode的代碼允許訪問所有系統(tǒng)內(nèi)存和所有CPU指令。?在User Mode下,http.sys接收到一個基于aspx的http request,然后它會根據(jù)IIS中的Metabase查看該基于該Request的Application屬于哪個Application Pool,如果該Application Pool不存在,則創(chuàng)建之。否則直接將request發(fā)到對應(yīng)Application Pool的Queue中。摘自:http://www.cnblogs.com/artech/archive/2007/09/09/887528.html
那允許單獨(dú)卸載每個應(yīng)用程序是怎么回事呢?
原因就是因為有隔離。Http請求被分放在相互隔離的應(yīng)用程序域中,當(dāng) Web.config文件的內(nèi)容發(fā)生改變 或者 .aspx文件發(fā)生變動的時候,能夠卸載運(yùn)行在同一個進(jìn)程中的應(yīng)用程序(卸載也是為了重新加載)。注:這也是為什么配置文件發(fā)生改變時,程序能立即更改,當(dāng)然這個還和接口有關(guān)系
3.為每個請求創(chuàng)建 ASP.NET 核心對象
創(chuàng)建了應(yīng)用程序域并對?HostingEnvironment?對象進(jìn)行了實例化之后,ASP.NET 將創(chuàng)建并初始化核心對象,如?HttpContext、HttpRequest?和HttpResponse。
MSDN備注:HostingEnvironment?構(gòu)造函數(shù)初始化?HostingEnvironment?對象。?HostingEnvironment?構(gòu)造函數(shù)僅由應(yīng)用程序的?ApplicationManager?對象調(diào)用一次
- HttpContext?類包含特定于當(dāng)前應(yīng)用程序請求的對象,如?HttpRequest?和?HttpResponse?對象。
- HttpRequest?對象包含有關(guān)當(dāng)前請求的信息,包括 Cookie 和瀏覽器信息。
- HttpResponse?對象包含發(fā)送到客戶端的響應(yīng),包括所有呈現(xiàn)的輸出和 Cookie。
上面是MSDN的描述。下面是了解到初始化Asp.Net核心對象的過程,主要是通過反編譯,我覺得合理。
?IIS接到一個針對動態(tài)頁面(.aspx)的請求,自己處理不了,就調(diào)用aspnet_isapi.dll這個服務(wù)器擴(kuò)展程序,再有aspnet_isapi.dll將請求交給ASP.NET,也就是一個名為aspnet_wp.exe的工作進(jìn)程。aspnet_wp.exe就調(diào)用FrameWork里的類 ------- ISAPIRuntime。
我們來看看ISAPIRuntime的類:public sealed class ISAPIRuntime : MarshalByRefObject,?IISAPIRuntime,?IRegisteredObject
分析:
a.繼承MarshalByRefObject:從而以此獲得跨應(yīng)用程序訪問對象的能力。
b.實現(xiàn) IISAPIRuntime接口,來看下這個接口里一個最重要的方法:
+ View Code
??注意看第一個參數(shù):IntPtr ecb,是一個指針對象,其實就是保存的aspnet_isapi.dll的引用,為什么要位ProcessRequest方法傳入這個指針?因為ASP.NET需要通過這個指針對應(yīng)的aspnet_isapi.dll對象 從IIS處獲得瀏覽器發(fā)來的請求報文,并且當(dāng)ASP.NET最后處理完頁面生成響應(yīng)報文后,也要通過它將響應(yīng)報文發(fā)回給IIS再有IIS發(fā)回到瀏覽器。
?c.繼承MarshalByRefObject的原因也就是為了能訪問到托管代碼外的這個aspnet_isapi.dll。
在ISAPIRuntime中調(diào)用了實現(xiàn)了接口IISAPIRuntime 的方法ProcessRequest。此方法中做了兩重大的事情:
?a.創(chuàng)建WorkerRequest對象:通過調(diào)用CreateWorkerRequest (IntPtr ecb, bool useOOP)方法來創(chuàng)建一個ISAPIWorkerRequest對象,此對象中包含了請求報文,并擁有和aspnet_isapi.dll通訊的能力。
?b. 調(diào)用HttpRuntime.ProcessRequestNoDemand(HttpWorkerRequest wr)方法,然后在此方法里通過調(diào)用HttpRuntime實例方法ProcessRequestInternal(HttpWorkerRequest wr),開始處理請求。
HttpRuntime中調(diào)用的ProcessRequestInternal(HttpWorkerRequest wr)做了3個重要的事情:
?a.生成上下文對象(HttpContext),為上下文對象context內(nèi)部的兩個重要的成員賦值:Reqeust和Response,前者負(fù)責(zé)向ASP.NET和程序員提供請求報文的數(shù)據(jù),后者向ASP.NET和程序員提供儲存要輸出到瀏覽器的數(shù)據(jù)的地方。
????????? (I).內(nèi)部的HttpRequest對象:根據(jù)wr里封裝的報文數(shù)據(jù)進(jìn)一步封裝出了HttpRequest對象。
????????? (II).內(nèi)部的HttpResponse對象:在內(nèi)部初始化了一個HtmlWriter對象,用來保存服務(wù)端要輸出給瀏覽器的頁面代碼。
????????? (III).注意,如果在創(chuàng)建context時出現(xiàn)錯誤,比如瀏覽器發(fā)來的請求報文格式錯誤,那么就會直接在此時向瀏覽器輸出400響應(yīng)報文。
?b.創(chuàng)建HttpApplication handler,此對象中執(zhí)行請求的動態(tài)頁面對象創(chuàng)建和執(zhí)行的整個過程。
(I).通過HttpApplicationFactory創(chuàng)建——HttpApplicationFactory.GetApplicationInstance(context) ;(具體方法)。注意:此方法中為創(chuàng)建的HttpApplication對象傳入了上下文對象context。
(II).HttpApplication具體執(zhí)行過程。
?c.當(dāng)HttpApplication執(zhí)行完后,調(diào)用FinishRequest方法,生成并輸出響應(yīng)報文到瀏覽器。
創(chuàng)建WorkerRequest對象,并HttpRuntime中調(diào)用的ProcessRequestInternal(HttpWorkerRequest wr)之后的大致流程:
?
MSDN對HttpRuntime的解釋:為當(dāng)前應(yīng)用程序提供一組 ASP.NET 運(yùn)行時服務(wù)。HttpRuntime?對象在處理 HTTP 請求的?ASP.NET 管線模型的開頭使用。?ProcessRequest 方法驅(qū)動所有后續(xù)的 ASP.NET Web 處理(注:ProcessRequest是HttpRuntime的方法,和IHttpHandler類似)。網(wǎng)頁開發(fā)人員可以使用?HttpRuntime?類屬性來查找關(guān)于當(dāng)前應(yīng)用程序域的信息,例如用于診斷目的。?創(chuàng)建自定義進(jìn)程管線或自定義宿主環(huán)境的開發(fā)人員應(yīng)該在從 HttpWorkerRequest 或 SimpleWorkerRequest 類派生的類中調(diào)用 ProcessRequest 方法。
?
我們按編號再來看一下這幅圖中的數(shù)據(jù)是如何流動的。具體的請看下文。
- ?HttpRuntime將請求轉(zhuǎn)交給 HttpApplicationFactory。HttpApplicationFactory(HttpApplicantFactory工廠)創(chuàng)建HttpApplication(為什么要用工廠?請參考:http://www.cnblogs.com/whtydn/archive/2009/10/16/1584584.html)。
- 接下來請求通過一系列Module。
- 請求經(jīng)過所有的Module之后,流轉(zhuǎn)到Handler進(jìn)一步處理。
- Handler處理完以后,請求再一次回到Module,此時Module可以做一些某個工作已經(jīng)完成了之后的事情。
?4.將HttpApplication對象分配給請求
?初始化所有核心應(yīng)用程序?qū)ο笾?#xff0c;將通過創(chuàng)建?HttpApplication?類的實例啟動應(yīng)用程序。?如果應(yīng)用程序具有 Global.asax 文件(ps:此時文件已經(jīng)加載了,config中的配置可能也讀取了),則 ASP.NET 會創(chuàng)建 Global.asax 類(從?HttpApplication?類派生)的一個實例,并使用該派生類表示應(yīng)用程序。?創(chuàng)建?HttpApplication?的實例時,將同時創(chuàng)建所有已配置的模塊。?例如,如果將應(yīng)用程序這樣配置,ASP.NET 就會創(chuàng)建一個?SessionStateModule?模塊(ps:此處是創(chuàng)建了包含自定義和原有的Module系列,并沒有執(zhí)行。也就是說:遍歷就是遍歷過濾器,為HttpApplicant里的事件注冊用戶方法)。?創(chuàng)建了所有已配置的模塊之后,將調(diào)用HttpApplication?類的?Init?方法(ps:Init方法并不是開啟管道的方法,Msdn:在添加所有事件處理程序模塊之后執(zhí)行自定義初始化代碼。)。
下面的關(guān)系圖說明了這種關(guān)系:
?那SessionStateModule是什么呢??怎么樣配置自定義的IhttpModule呢?
ASP.NET 應(yīng)用程序生命周期可通過?IHttpModule?類進(jìn)行擴(kuò)展。?ASP.NET 包含若干實現(xiàn)?IHttpModule?的類,如?SessionStateModule?類。?您還可以自行創(chuàng)建實現(xiàn)?IHttpModule?的類。這時也就知道SessionStateModule是實現(xiàn)IHttpModule接口的類而已。(關(guān)于IHttpModule只是點(diǎn)到而已,具體請參考:http://www.cnblogs.com/JimmyZhang/archive/2007/11/25/971878.html)
?關(guān)于Module請參考:http://www.cnblogs.com/anlen/articles/3613186.html
?MSDN:http://msdn.microsoft.com/zh-cn/library/system.web.ihttpmodule(v=vs.100).aspx
?關(guān)于Handler請參考:http://www.cnblogs.com/anlen/articles/3613204.html
MSDN:http://msdn.microsoft.com/zh-cn/library/system.web.ihttphandler(v=vs.110).aspx
通過HttpApplicationFactory創(chuàng)建了一個HttpApplicant對象,負(fù)責(zé)處理整個請求,是通過創(chuàng)建?HttpApplication?類的實例啟動應(yīng)用程序。
5.由HttpApplication管線處理請求
?在處理該請求時將由?HttpApplication?類執(zhí)行以下事件。?希望擴(kuò)展?HttpApplication?類的開發(fā)人員需要注意這些事件。
?1.對請求進(jìn)行驗證,將檢查瀏覽器發(fā)送的信息,并確定其是否包含潛在惡意標(biāo)記。?有關(guān)更多信息,請參見ValidateRequest?和腳本侵入概述。
2.如果已在 Web.config 文件的?UrlMappingsSection?節(jié)中配置了任何 URL,則執(zhí)行 URL 映射。
3.引發(fā)?BeginRequest?事件。
在 ASP.NET 響應(yīng)請求時作為 HTTP 執(zhí)行管線鏈中的第一個事件發(fā)生。BeginRequest?事件發(fā)出信號表示創(chuàng)建任何給定的新請求。?此事件始終被引發(fā),并且始終是請求處理期間發(fā)生的第一個事件。
4.引發(fā)?AuthenticateRequest?事件。
當(dāng)安全模塊已建立用戶標(biāo)識時發(fā)生。AuthenticateRequest?事件發(fā)出信號表示配置的身份驗證機(jī)制已對當(dāng)前請求進(jìn)行了身份驗證。?訂閱?AuthenticateRequest?事件可確保在處理附加模塊或事件處理程序之前對請求進(jìn)行身份驗證。
5.引發(fā)?PostAuthenticateRequest?事件。
當(dāng)安全模塊已建立用戶標(biāo)識時發(fā)生。PostAuthenticateRequest?事件在?AuthenticateRequest?事件發(fā)生之后引發(fā)。?預(yù)訂?PostAuthenticateRequest?事件的功能可以訪問由PostAuthenticateRequest?處理的任何數(shù)據(jù)。
6.引發(fā)?AuthorizeRequest?事件。
當(dāng)安全模塊已驗證用戶授權(quán)時發(fā)生。AuthorizeRequest?事件發(fā)出信號表示 ASP.NET 已對當(dāng)前請求進(jìn)行了授權(quán)。?訂閱?AuthorizeRequest?事件可確保在處理附加的模塊或事件處理程序之前對請求進(jìn)行身份驗證和授權(quán)。
7.引發(fā)?PostAuthorizeRequest?事件。
在當(dāng)前請求的用戶已獲授權(quán)時發(fā)生。PostAuthorizeRequest?事件發(fā)出信號表示 ASP.NET 已對當(dāng)前請求進(jìn)行了授權(quán)。?訂閱?PostAuthorizeRequest?事件可確保在處理附加的模塊或處理程序之前對請求進(jìn)行身份驗證和授權(quán)。
8.引發(fā)?ResolveRequestCache?事件。
在 ASP.NET 完成授權(quán)事件以使緩存模塊從緩存中為請求提供服務(wù)后發(fā)生,從而繞過事件處理程序(例如某個頁或 XML Web services)的執(zhí)行。
9.引發(fā)?PostResolveRequestCache?事件。
在 ASP.NET 跳過當(dāng)前事件處理程序的執(zhí)行并允許緩存模塊滿足來自緩存的請求時發(fā)生。
10.根據(jù)所請求資源的文件擴(kuò)展名(在應(yīng)用程序的配置文件中映射),選擇實現(xiàn)?IHttpHandler?的類,對請求進(jìn)行處理。如果該請求針對從?Page?類派生的對象(頁),并且需要對該頁進(jìn)行編譯,則 ASP.NET 會在創(chuàng)建該頁的實例之前對其進(jìn)行編譯。
11.引發(fā)?PostMapRequestHandler?事件。
在 ASP.NET 已將當(dāng)前請求映射到相應(yīng)的事件處理程序時發(fā)生。
12.引發(fā)?AcquireRequestState?事件。
當(dāng) ASP.NET 獲取與當(dāng)前請求關(guān)聯(lián)的當(dāng)前狀態(tài)(如會話狀態(tài))時發(fā)生。AcquireRequestState?事件在創(chuàng)建了事件處理程序之后引發(fā)。
13.引發(fā)?PostAcquireRequestState?事件。
在已獲得與當(dāng)前請求關(guān)聯(lián)的請求狀態(tài)(例如會話狀態(tài))時發(fā)生。PostAcquireRequestState?事件在?AcquireRequestState?事件發(fā)生之后引發(fā)。?預(yù)訂?AcquireRequestState?事件的功能可以訪問由PostAcquireRequestState?處理的任何數(shù)據(jù)。
14.引發(fā)?PreRequestHandlerExecute?事件。
恰好在 ASP.NET 開始執(zhí)行事件處理程序(例如,某頁或某個 XML Web services)前發(fā)生。
15.為該請求調(diào)用合適的?IHttpHandler?類的?ProcessRequest?方法(或異步版IHttpAsyncHandler.BeginProcessRequest)。?例如,如果該請求針對某頁,則當(dāng)前的頁實例將處理該請求。
16.引發(fā)?PostRequestHandlerExecute?事件。
在 ASP.NET 已將當(dāng)前請求映射到相應(yīng)的事件處理程序時發(fā)生。
17.引發(fā)?ReleaseRequestState?事件。
在 ASP.NET 已將當(dāng)前請求映射到相應(yīng)的事件處理程序時發(fā)生。
18.引發(fā)?PostReleaseRequestState?事件。
在 ASP.NET 已完成所有請求事件處理程序的執(zhí)行并且請求狀態(tài)數(shù)據(jù)已存儲時發(fā)生。
19.如果定義了?Filter?屬性,則執(zhí)行響應(yīng)篩選。
20.引發(fā)?UpdateRequestCache?事件。
當(dāng) ASP.NET 執(zhí)行完事件處理程序以使緩存模塊存儲將用于從緩存為后續(xù)請求提供服務(wù)的響應(yīng)時發(fā)生。
21.引發(fā)?PostUpdateRequestCache?事件。
在 ASP.NET 完成緩存模塊的更新并存儲了用于從緩存中為后續(xù)請求提供服務(wù)的響應(yīng)后,發(fā)生此事件。
22.引發(fā)?EndRequest?事件。
在 ASP.NET 響應(yīng)請求時作為 HTTP 執(zhí)行管線鏈中的最后一個事件發(fā)生。
23.引發(fā)?PreSendRequestHeaders?事件。
恰好在 ASP.NET 向客戶端發(fā)送 HTTP 標(biāo)頭之前發(fā)生。
24.引發(fā)?PreSendRequestContent?事件。
恰好在 ASP.NET 向客戶端發(fā)送內(nèi)容之前發(fā)生。PreSendRequestContent?事件可能發(fā)生多次。
IIS6中共有24個事件,其中有19個事件是我們可以進(jìn)行控制的。因為這些都是事件,所以可以往里面添加多個自定義方法。通常說的事件是從BeginRequest開始的。先通過一張圖來了解下這些事件是在什么地方執(zhí)行的。
?
M:客戶端請求處理開始,前六個事件是在HttpModule中處理的,這六個事件是我們可以調(diào)用的,分別是:BeginRequest、AuthenticateRequest、AuthorizeRequest、ResolveRequestCache、AcquireRequestState和PreRequestHandlerExecute。(ps:HttpModule不只是一個,這六個可在Application中控制)。
H:執(zhí)行Handler中的PracessRequest()。(ps:Handler也不止一個)。
P:一旦HttpHandler邏輯執(zhí)行,ASP.NET的page對象被創(chuàng)建(ps:Page繼承的接口有IHttpHandle)。ASP.NET page對象被創(chuàng)建,許多事件被觸發(fā),你可以在這些頁面事件中寫我們自定義的邏輯。有6個重要事件給我們提供占位,在ASP.NET頁中寫邏輯:Init、Load、Validate、Event、Render、Unload。你可以記住單詞SILVER來記這些事件,S-Start(沒有任何意義,僅僅是為了形成一個單詞),I(Init)、L(Load)、V(Validate)、E(Event)、R(Render)。其實還是HttpHandler中的事件。
M:一旦頁面對象執(zhí)行了且從內(nèi)存中卸載,HttpModule提供發(fā)送頁面執(zhí)行事件,它們可用于注入自定義post-處理邏輯。有4個重要的post-處理事件,PostRequestHandlerExecute、PostRequestState、UpdateRequestCache、EndRequest。
添加方法如下:
應(yīng)用程序的生命周期中的添加方法:通過使用命名約定?Application_event(如?Application_BeginRequest),ASP.NET 可在 Global.asax 文件中將應(yīng)用程序事件自動綁定到處理程序。(為什么可以在Global.asax中添加方法?因為Global.asax與HttpApplication是繼承關(guān)系。)。此處能添加的事件有19個,如下圖所示:
?IHttpModule中方法的調(diào)用:可以自定義post-處理邏輯。果向應(yīng)用程序添加模塊,模塊本身會引發(fā)事件。?通過使用?modulename_eventname?約定,應(yīng)用程序可以在 Global.asax 文件中預(yù)訂這些事件。?例如,若要處理?FormsAuthenticationModule?對象引發(fā)的?Authenticate?事件,可以創(chuàng)建一個名為FormsAuthentication_Authenticate?的處理程序。默認(rèn)情況下,ASP.NET 中會啟用?SessionStateModule?類。?所有會話事件自動命名為?Session_event,如?Session_Start。?每次創(chuàng)建新會話時都會引發(fā)?Start?事件。
還有特殊如:Application_Start、Application_event、Init?、Dispose、Application_End等。
頁還支持自動事件連接,即,ASP.NET 將查找具有特定名稱的方法,并在引發(fā)了特定事件時自動運(yùn)行這些方法。?如果?@?Page指令的?AutoEventWireup?特性設(shè)置為?true,頁事件將自動綁定至使用命名約定?Page_事件(如?Page_Load?和?Page_Init)的方法。可參考。還有:當(dāng)您創(chuàng)建從?Page?類繼承的類時,除了可以處理由頁引發(fā)的事件以外,還可以重寫頁的基類中的方法。
?下面再整體看下流程圖,具體都做了那些事情:聲明:這兩幅圖不是本人所畫,是由鄒老師所畫。
注意:每一次請求都執(zhí)行這個過程(前提是沒有緩存),HttpContext保持單個用戶、單個請求的數(shù)據(jù),并且數(shù)據(jù)只在該請求期間保存。被提供用于保持需要在不同的HttpModules和HttpHandlers之間傳遞的值。也可以用于保持某個完整請求的相應(yīng)信息。 在請求管道中,第八個事件PostMapRequestHandler中創(chuàng)建頁面對象,并轉(zhuǎn)換成HttpHandler接口;第九個事件加載Session事件,先判斷當(dāng)前頁面是否實現(xiàn)了IRequiresSessionState接口,如果實現(xiàn)了,則從瀏覽器發(fā)來的請求報文中獲得Cookie里的SessionID,然后到服務(wù)器Session池中獲得對應(yīng)的Session對象,并將其引用賦值給頁面對象的Session屬性(Page.HttpContext.HttpSession)。接下來在第十一個和第十二個事件調(diào)用頁面對象的ProcessPequest(HttpContext context),頁面也是繼承IHttpHandler的對象。進(jìn)入是一個和第二個事件之后就是頁面的生命周期了,具體請看下回分解。
如果我們將注意力只集中在請求、HttpHandler和HttpModule上,不去考慮HttpContext和HttpApplication,可以將請求簡化成下面這樣:
?
參考:http://www.cnblogs.com/skynet/archive/2010/04/29/1724020.html????介紹Module中的事件。
http://www.cnblogs.com/artech/archive/2007/09/09/887528.html? IIS 解釋
http://www.cnblogs.com/artech/archive/2009/06/20/1507165.html?管道事件
Application Restarts(應(yīng)用程序重新啟動的次數(shù))
?修改 Web 應(yīng)用程序的源代碼將導(dǎo)致 ASP.NET 把源文件重新編譯為程序集。?當(dāng)修改應(yīng)用程序中的頂級項時,應(yīng)用程序中引用頂級程序集的其他所有程序集也會被重新編譯。
此外,修改、添加或刪除應(yīng)用程序的已知文件夾中的某些類型的文件將導(dǎo)致應(yīng)用程序重新啟動。?下列操作將導(dǎo)致應(yīng)用程序重新啟動:?
-
添加、修改或刪除應(yīng)用程序的 Bin 文件夾中的程序集。
-
添加、修改或刪除 App_GlobalResources 或 App_LocalResources 文件夾中的本地化資源。
-
添加、修改或刪除應(yīng)用程序的 Global.asax 文件。
-
添加、修改或刪除 App_Code 目錄中的源代碼文件。
-
添加、修改或刪除配置文件配置。
-
添加、修改或刪除 App_WebReferences 目錄中的 Web 服務(wù)引用。
-
添加、修改或刪除應(yīng)用程序的 Web.config 文件。
當(dāng)應(yīng)用程序需要重新啟動時,ASP.NET 將在重新啟動應(yīng)用程序域和加載新的程序集之前,從現(xiàn)有應(yīng)用程序域和舊的程序集中為所有掛起的請求提供服務(wù)。
頁生命周期、控件生命周期,請看下回分解。
圖解請看:
請參考:http://www.cnblogs.com/zhaoyang/archive/2011/11/16/2251200.html ??圖解生命周期
接下來就是:Asp.net的生命周期之頁生命周期(生命周期概述二)
總結(jié)
以上是生活随笔為你收集整理的【转】Asp.net的生命周期之应用程序生命周期的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为拍出"氛围感" 女孩含夹竹桃后中毒!网
- 下一篇: VB编程语言简史