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