標籤:
原文:ASP.NET 應用程式(Application)生命週期概述
引用MSDN:ASP.NET 應用程式生命週期概述
本主題概述應用程式生命週期,列出重要的生命週期事件,並描述如何編寫適合應用程式生命週期的代碼。在 ASP.NET 中,若要對 ASP.NET應用程式進行初始化並使它處理請求,必須執行一些處理步驟。此外,ASP.NET 只是對瀏覽器發出的請求進行處理的 Web伺服器結構的一部分。瞭解應用程式生命週期非常重要,這樣才能在適當的生命週期階段編寫代碼,達到預期的效果。
應用程式生命週期概述
下表描述了 ASP.NET 應用程式生命週期的各個階段。
| 階段 |
說明 |
| 使用者從 Web 服務器請求應用程式資源。 |
ASP.NET 應用程式的生命週期以瀏覽器向 Web 服務器(對於 ASP.NET 應用程式,通常為 IIS)發送請求為起點。ASP.NET 是 Web 伺服器下的 ISAPI 擴充。Web 服務器接收到請求時,會對所請求的檔案的副檔名進行檢查,確定應由哪個 ISAPI 擴充處理該請求,然後將該請求傳遞給合適的 ISAPI 擴充。ASP.NET 處理已映射到其上的副檔名,如 .aspx、.ascx、.ashx 和 .asmx。
| 注意 |
| 如 果副檔名尚未映射到 ASP.NET,則 ASP.NET 將不會接收該請求。對於使用 ASP.NET 身分識別驗證的應用程式,理解這一點非常重要。例如,由於 .htm 檔案通常沒有映射到 ASP.NET,因此 ASP.NET 將不會對 .htm 檔案請求執行身分識別驗證或授權檢查。因此,即使檔案僅包含靜態內容,如果希望 ASP.NET 檢查身分識別驗證,也應使用映射到 ASP.NET 的副檔名建立該檔案,如採用副檔名 .aspx。 |
| 注意 |
| 如果要建立服務於特定副檔名的自訂處理常式,必須在 IIS 中將該副檔名映射到 ASP.NET,還必須在應用程式的 Web.config 檔案中註冊該處理常式。有關更多資訊,請參見 HTTP 處理常式介紹。 |
|
| ASP.NET 接收對應用程式的第一個請求。 |
當 ASP.NET 接收到對應用程式中任何資源的第一個請求時,名為 ApplicationManager 的類會建立一個應用程式定義域。應用程式定義域為全域變數提供應用程式隔離,並允許單獨卸載每個應用程式。在應用程式定義域中,將為名為 HostingEnvironment 的類建立一個執行個體,該執行個體提供對有關應用程式的資訊(如儲存該應用程式的檔案夾的名稱)的訪問。 下面的關係圖說明了這種關係: 如果需要,ASP.NET 還可對應用程式中的頂級項進行編譯,其中包括 App_Code 檔案夾中的應用程式代碼。有關更多資訊,請參見本主題後面的“編譯生命週期”。 |
| 為每個請求建立 ASP.NET 核心對象。 |
建立了應用程式定義域並對 HostingEnvironment 對象進行了執行個體化之後,ASP.NET 將建立並初始化核心對象,如 HttpContext、HttpRequest 和 HttpResponse。HttpContext 類包含特定於當前應用程式請求的對象,如 HttpRequest 和 HttpResponse 對象。HttpRequest 對象包含有關當前請求的資訊,包括 Cookie 和瀏覽器資訊。HttpResponse 對象包含發送到用戶端的響應,包括所有轉譯輸出和 Cookie。 |
| 將 HttpApplication 對象分配給請求 |
初始化所有核心應用程式物件之後,將通過建立 HttpApplication 類的執行個體啟動應用程式。如果應用程式具有 Global.asax 檔案,則 ASP.NET 會建立 Global.asax 類(從 HttpApplication 類派生)的一個執行個體,並使用該衍生類別表示應用程式。
| 注意 |
| 第一次在應用程式中請求 ASP.NET 頁或進程時,將建立 HttpApplication 的一個新執行個體。不過,為了儘可能提高效能,可對多個請求重複使用 HttpApplication 執行個體。 |
建立 HttpApplication 的執行個體時,將同時建立所有已配置的模組。例如,如果將應用程式這樣配置,ASP.NET 就會建立一個 SessionStateModule 模組。建立了所有已配置的模組之後,將調用HttpApplication 類的 Init 方法。 下面的關係圖說明了這種關係: |
| 由 HttpApplication 管線處理請求。 |
在處理該請求時將由 HttpApplication 類執行以下事件。希望擴充 HttpApplication 類的開發人員尤其需要注意這些事件。
-
對請求進行驗證,將檢查瀏覽器發送的資訊,並確定其是否包含潛在惡意標記。有關更多資訊,請參見 ValidateRequest 和指令碼侵入概述。
-
如果已在 Web.config 檔案的 UrlMappingsSection 節中配置了任何 URL,則執行 URL 對應。
-
引發 BeginRequest 事件。
-
引發 AuthenticateRequest 事件。
-
引發 PostAuthenticateRequest 事件。
-
引發 AuthorizeRequest 事件。
-
引發 PostAuthorizeRequest 事件。
-
引發 ResolveRequestCache 事件。
-
引發 PostResolveRequestCache 事件。
-
根據所請求資源的副檔名(在應用程式的設定檔中映射),選擇實現 IHttpHandler 的類,對請求進行處理。如果該請求針對從 Page 類派生的對象(頁),並且需要對該頁進行編譯,則 ASP.NET 會在建立該頁的執行個體之前對其進行編譯。
-
引發 PostMapRequestHandler 事件。
-
引發 AcquireRequestState 事件。
-
引發 PostAcquireRequestState 事件。
-
引發 PreRequestHandlerExecute 事件。
-
為該請求調用合適的 IHttpHandler 類的 ProcessRequest 方法(或非同步版 BeginProcessRequest)。例如,如果該請求針對某頁,則當前的頁執行個體將處理該請求。
-
引發 PostRequestHandlerExecute 事件。
-
引發 ReleaseRequestState 事件。
-
引發 PostReleaseRequestState 事件。
-
如果定義了 Filter 屬性,則執行響應篩選。
-
引發 UpdateRequestCache 事件。
-
引發 PostUpdateRequestCache 事件。
-
引發 EndRequest 事件。
|
生命週期事件和 Global.asax 檔案
在應用程式的生命週期期間,應用程式會引發可處理的事件並調用可重寫的特定方法。若要處理應用程式事件或方法,可以在應用程式根目錄中建立一個名為 Global.asax 的檔案。
如果建立了 Global.asax 檔案,ASP.NET 會將其編譯為從 HttpApplication 類派生的類,然後使用該衍生類別表示應用程式。
HttpApplication進程的一個執行個體每次只處理一個請求。由於在訪問應用程式類中的非靜態成員時不需要將其鎖定,這樣可以簡化應用程式的事件處理過程。這樣還可以將特定於請求的資料存放區在應用程式類的非靜態成員中。例如,可以在 Global.asax 檔案中定義一個屬性,然後為該屬性賦一個特定於請求的值。
通過使用命名規範 Application_event(如 Application_BeginRequest),ASP.NET 可在 Global.asax 檔案中將應用程式事件自動綁定到處理常式。這與將 ASP.NET 頁方法自動綁定到事件(如頁的 Page_Load 事件)的方法類似。有關詳細資料,請參見 ASP.NET 頁生命週期概述。
Application_Start 和 Application_End 方法是不表示 HttpApplication 事件的特殊方法。在應用程式定義域的生命週期期間,ASP.NET 僅調用這些方法一次,而不是對每個 HttpApplication 執行個體都調用一次。
下表列出在應用程式生命週期期間使用的一些事件和方法。實際遠不止列出的這些事件,但這些事件是最常用的。
| 事件或方法 |
說明 |
| Application_Start |
請求 ASP.NET 應用程式中第一個資源(如頁)時調用。在應用程式的生命週期期間僅調用一次 Application_Start 方法。可以使用此方法執行啟動任務,如將資料載入到緩衝中以及初始化靜態值。 在應用程式啟動期間應僅設定待用資料。由於執行個體資料僅可由建立的 HttpApplication 類的第一個執行個體使用,所以請勿設定任何執行個體資料。 |
| Application_ event |
在應用程式生命週期中的適當時候引發,請參見本主題前面的應用程式生命週期表中列出的內容。 Application_Error 可在應用程式生命週期的任何階段引發。 由於請求會短路,因此 Application_EndRequest 是唯一能保證每次請求時都會引發的事件。例如,如果有兩個模組處理 Application_BeginRequest 事件,第一個模組引發一個異常,則不會為第二個模組調用 Application_BeginRequest 事件。但是,會始終調用 Application_EndRequest 方法使應用程式清理資源。 |
| HttpApplication.Init |
在建立了所有模組之後,對 HttpApplication 類的每個執行個體都調用一次。 |
| Dispose |
在銷毀應用程式執行個體之前調用。可使用此方法手動釋放任何非託管資源。有關更多資訊,請參見清理非託管資源。 |
| Application_End |
在卸載應用程式之前對每個應用程式生命週期調用一次。 |
編譯生命週期
在第一次對應用程式發出請求時,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 檔案) |
根據需要編譯並連結到本地資來源程式集和頂級程式集。 |
| 主題、主控頁、其他源檔案 |
在編譯引用頁時編譯那些頁所引用的各個主題、主控頁和其他原始碼檔案的面板檔案。 |
編譯後的組件快取在伺服器上並在後續請求時被重用,並且只要原始碼未更改,就會在應用程式重新啟動之間得到保留。
由於應用程式在第一次請求時進行編譯,所以對應用程式的初始請求所花的時間會明顯長於後續請求。可以先行編譯應用程式以減少第一次請求所需的時間。有關更多資訊,請參見如何:先行編譯 ASP.NET 網站。
Application Restarts(應用程式重新啟動的次數)
修改 Web 應用程式的原始碼將導致 ASP.NET 把源檔案重新編譯為程式集。當修改應用程式中的頂級項時,應用程式中引用頂級程式集的其他所有程式集也會被重新編譯。
此外,修改、添加或刪除應用程式的已知檔案夾中的某些類型的檔案將導致應用程式重新啟動。下列操作將導致應用程式重新啟動:
-
添加、修改或刪除應用程式的 Bin 檔案夾中的程式集。
-
添加、修改或刪除 App_GlobalResources 或 App_LocalResources 檔案夾中的本地化資源。
-
添加、修改或刪除應用程式的 Global.asax 檔案。
-
添加、修改或刪除 App_Code 目錄中的原始碼檔案。
-
添加、修改或刪除設定檔配置。
-
添加、修改或刪除 App_WebReferences 目錄中的 Web 服務參考。
-
添加、修改或刪除應用程式的 Web.config 檔案。
當應用程式需要重新啟動時,ASP.NET 將在重新啟動應用程式定義域和載入新的程式集之前,從現有應用程式定義域和舊的程式集中為所有掛起的請求提供服務。
HTTP 模組
ASP.NET 應用程式生命週期可通過 IHttpModule 類進行擴充。ASP.NET 包含若干實現 IHttpModule 的類,如 SessionStateModule 類。您還可以自行建立實現 IHttpModule 的類。
如果嚮應用程式添加模組,模組本身會引發事件。通過使用 modulename_eventname 約定,應用程式可以在 Global.asax 檔案中預訂這些事件。例如,若要處理 FormsAuthenticationModule 對象引發的 Authenticate 事件,可以建立一個名為 FormsAuthentication_Authenticate 的處理常式。
預設情況下,ASP.NET 中會啟用 SessionStateModule 類。所有會話事件將自動命名為 Session_event,如 Session_Start。每次建立新會話時都會引發 Start 事件。有關更多資訊,請參見工作階段狀態概述。
ASP.NET 應用程式(Application)生命週期概述