天天看點

Aspx 頁面生命周期

ASP.NET 頁運作時,此頁将經曆一個生命周期,在生命周期中将執行一系列處理步驟。這些步驟包括初始化、執行個體化控件、還原和維護狀态、運作事件處理程式代碼以及進行呈現。了解頁的生命周期非常重要,這樣就能在合适的生命周期階段編寫代碼,以達到預期效果。此外,如果開發自定義控件,則必須熟悉頁生命周期,進而正确地初始化控件,使用視圖狀态資料填充控件屬性以及運作所有控件行為邏輯。(控件的生命周期基于頁的生命周期,但是頁引發的控件事件比單獨的 ASP.NET 頁中可用的事件多。)

正常頁生命周期階段

一般來說,頁要經曆下表概述的各個階段。除了頁生命周期階段以外,還有在請求前後出現的應用程式階段,但是這些階段并不特定于頁。有關更多資訊,請參見 ASP.NET 應用程式生命周期概述。

階段

說明

頁請求

頁請求發生在頁生命周期開始之前。使用者請求頁時,ASP.NET 将确定是否需要分析和編譯頁(進而開始頁的生命周期),或者是否可以在不運作頁的情況下發送頁的緩存版本以進行響應。

開始

在開始階段,将設定頁屬性,如 Request 和 Response。在此階段,頁還将确定請求是回發請求還是新請求,并設定 IsPostBack 屬性。此外,在開始階段期間,還将設定頁的 UICulture 屬性。

頁初始化

頁初始化期間,可以使用頁中的控件,并将設定每個控件的 UniqueID 屬性。此外,任何主題都将應用于頁。如果目前請求是回發請求,則回發資料尚未加載,并且控件屬性值尚未還原為視圖狀态中的值。

加載

加載期間,如果目前請求是回發請求,則将使用從視圖狀态和控件狀态恢複的資訊加載控件屬性。

驗證

在驗證期間,将調用所有驗證程式控件的 Validate 方法,此方法将設定各個驗證程式控件和頁的 IsValid 屬性。

回發事件處理

如果請求是回發請求,則将調用所有事件處理程式。

呈現

在呈現期間,視圖狀态将被儲存到頁,然後頁将調用每個控件,以将其呈現的輸出提供給頁的 Response 屬性的 OutputStream。

解除安裝

完全呈現頁、将頁發送至用戶端并準備丢棄時,将調用解除安裝。此時,将解除安裝頁屬性(如 Response 和 Request)并執行清理。

生命周期事件

在頁生命周期的每個階段中,頁将引發可運作您自己的代碼進行處理的事件。對于控件事件,通過以聲明方式使用屬性(如 onclick)或以使用代碼的方式,均可将事件處理程式綁定到事件。

頁還支援自動事件連接配接,即,ASP.NET 将尋找具有特定名稱的方法,并在引發特定事件時自動運作這些方法。如果 @ Page 指令的 AutoEventWireup 屬性設定為 true(或者如果未定義該屬性,因為預設情況下為 true),頁事件将自動綁定至使用 Page_event 命名約定的方法,如 Page_Load 和 Page_Init。有關自動事件連接配接的更多資訊,請參見 ASP.NET Web 伺服器控件事件模型。

下表列出了最常用的頁生命周期事件。實際的事件比列出的事件要多。但是,它們不用于大多數頁處理方案。而是主要由 ASP.NET 網頁上的伺服器控件使用,以初始化和呈現它們本身。如果要編寫自己的 ASP.NET 伺服器控件,則需要詳細了解這些階段。有關建立自定義控件的資訊,請參見開發自定義 ASP.NET 伺服器控件。

頁事件

典型使用

Page_PreInit

使用 IsPostBack 屬性确定是否是第一次處理該頁。

建立或重新建立動态控件。

動态設定主要頁。

動态設定 Theme 屬性。

讀取或設定配置檔案屬性值。

注意

如果請求是回發請求,則控件的值尚未從視圖狀态還原。如果在此階段設定控件屬性,則其值可能會在下一階段被改寫。

Page_Init

讀取或初始化控件屬性。

Page_Load

讀取和更新控件屬性。

Control events

執行特定于應用程式的處理:

如果頁包含驗證程式控件,請在執行任何處理之前檢查頁和各個驗證控件的 IsValid 屬性。

處理特定事件,如 Button 控件的 Click 事件。

Page_PreRender

對頁的内容進行最後更改。

Page_Unload

執行最後的清理工作,可能包括:

關閉打開的檔案和資料庫連接配接。

完成日志記錄或其他特定于請求的任務。

在解除安裝階段,頁及其控件已被呈現,是以無法對響應流做進一步更改。如果嘗試調用方法(如 Response.Write 方法),則該頁将引發異常。

其他的頁生命周期注意事項

請注意有關頁生命周期的以下附加資訊:

各個 ASP.NET 伺服器控件都有自己的生命周期,該生命周期與頁生命周期類似。例如,在相應的頁事件期間将調用控件的 Init 和 Load 方法。如果頁上包含控件,則将首先調用控件的 Init 方法,然後再調用頁的 Init 方法。但是,将在調用控件的 Load 方法之前先調用頁的 Load 方法。

通過處理控件的事件,可以自定義控件的外觀或内容。例如,所有的控件都将引發 Init、Load 和 Unload 事件,但是頁開發人員通常不處理這些事件。而是通常處理特定于控件的事件,如 Button 控件的 Click 事件和 ListBox 控件的 SelectedIndexChanged 事件。在某些情況下,可能也需處理控件的 DataBinding 或 DataBound 事件。有關更多資訊,請參見各個控件的類參考主題以及開發自定義 ASP.NET 伺服器控件。

除了處理由頁引發的事件以外,還可以重寫頁的基類中的方法。例如,可以重寫頁的 InitializeCulture 方法,以便動态設定區域性資訊。注意,在使用 Page_event 文法建立事件處理程式時,将隐式調用基實作,是以無需在方法中調用它。例如,無論是否建立 Page_Load 方法,始終都會調用頁基類的 OnLoad 方法。但是,如果使用 override 關鍵字(在 Visual Basic 中為 Overrides)重寫頁的 OnLoad 方法,則必須顯式調用基方法。例如,如果在頁中重寫 OnLoad 方法,則必須調用 base.Load(在 Visual Basic 中為 MyBase.Load)以運作基實作。

具體階段執行函數的順序

初始化(Initialization)

頁面被請求時,第一個被執行的總是構造函數(constructor). 你可以在這裡初始化很多自定義屬性或對象。不過這裡有一些限制,因為 page 還沒有被完全初始化。特别地,你必須使用 HttpContext.Current 來通路 QueryString, Form, Cookies 集合,以及 Cache 對象。而 Session 對象在 constructor 裡是無法通路的。

下面接着執行的是 AddParsedSubObject 方法,這個方法把組成該 page 的所有子控件添加到控件集合樹中。在很多進階的頁面模闆解決方案中,該方法通常被覆寫,以便把頁面的控件添加到一個特殊的頁面模闆中去。該方法遞歸的被子控件調用,所有這些子控件都是這時候初始化的,從最裡面的開始。

接着是 DeterminePostBackMode 方法。該方法允許你影響 IsPostBack 的值,以及相關事件。如果你想從資料庫中加載 ViewState 以便 redirect 時,這個可能對你有用。因為 ViewState 僅僅在 IsPostBack 為 true 的時候被恢複。 你可以通過傳回 null 來強制不 postback, 或者傳回 Request.Form 來強制 postback. 這個方法是不推薦使用的,除非是在特殊的情況下,因為他還影響其他的事件。

然後是 OnInit 方法。通常這是我們使用到的第一個方法。這時,所有控件已經被初始化,也就是說所有原始值都被設定了。而 ViewState 以及所有其他 post 的值還沒有被應用到控件上。也就是說這時候所有通過代碼或者使用者操作做的更改還沒有被恢複。這通常是建立或重新建立動态控件的最佳時機。

恢複和加載(Restore and Load)

接下來的 LoadPageStateFromPersistenceMedium 方法,僅僅在 PostBack 時被執行。當你要改變儲存 ViewState 的方法時(使用 Session 或其他自定義的儲存方法),覆寫這個方法,以及後面的 SavePageStateToPersistenceMedium 方法。注意:該方法并不真正加載 ViewState 到 page 及其子控件。

ViewState 被取回後,接着 LoadViewState 方法将它們恢複到 page, 并遞歸的恢複到每一個子控件(隻有 PostBack 的那些).這時,每個控件已經被恢複到了它上次執行時的狀态,但使用者 post 的值還沒有被應用。因為這屬于 ViewState. 這個方法是恢複所有在事件中建立的動态控件的最好時機。

下一個是 ProcessPostData 方法。僅僅在 PostBack 時被執行。而且這個方法不能被覆寫,因為它是頁面基類中實作的一個私有方法。這個方法最終将使用者 post 的值,通過比對控件的名稱的方法,恢複到頁面。這時,page 已經被完全恢複了。動态控件必須在這個方法之前被建立。這個方法同時也為稍後的 changed 事件記錄控件值的改變。

然後才是 OnLoad 方法。大部分的代碼中都使用這個方法,因為這是在 page 的生命周期中,第一個所有的值都被恢複了的地方。我們可以通過檢查 IsPostBack 屬性來避免不必要的重設狀态。同時也可以檢查 IsValid 屬性來進行驗證。同時還可以在這裡建立動态控件。所有這些控件的方法都會被執行并捕獲,包括 ViewState. 但回發的值不可以。

Raised Events

下一個方法,ProcessPostData 方法,實際上是前面那個方法的第二個入口(second pass)。它僅僅處理回發,而且由于是私有方法,是以不能被覆寫。這個方法顯得有些奇怪,但又是必要的。因為在 OnLoad 方法中重建的動态控件需要他們回發的值。所有在這個方法之後建立的動态控件,将隻能恢複 ViewState, 而不能恢複回發的值,并且不能觸發任何更改事件。

下一個方法, RaiseChangedEvents, 同樣僅僅用于回發時。它是一個基類實作的私有方法。這時 changed 事件被真正觸發。這基于前面 ProcessPostData 方法中标注出回發的值的差異。當有多個 changed 事件被觸發時,其先後順序是沒有保證的。

下面是 RaisePostBackEvent 方法。僅用于回發,而且是基類實作的私有方法。這是真正送出 form 的方法,除非是 postback。比如按鈕,或者其他通過 javascript 送出的控件被觸發。如果使用了 Validators, 如沒有手動調用 Validate 方法,這時也已經被調用了。有時候 ie 的 bug 會使得表單被送出,而不引發事件。

接着是 OnPreRender 方法。這通常是在被繪制到浏覽器之前,要更改 page 及其子控件的最後機會。你也可以在這裡建立動态控件。但這時隻能捕獲 ViewState, 而不能接受 posted values, 而且沒有事件。因為上面提到的 ie 的 bug, 這裡可以用來捕獲沒有觸發事件的 post back.

儲存和繪制(Save and Render)

下一個是 SaveViewState 方法。不管是否 post back. 遞歸的應用到每一個子控件。ViewState 一般儲存所有和 aspx 頁面裡不一樣的屬性,不管是被代碼還是使用者更改的。注意,由于控件的值是通過他們在控件樹中的位置來儲存的,是以如果在這之後添加動态控件到錯誤的位置, ViewState 可能會崩潰。

下面是 SavePageStateToPersistenceMedium 方法。它真正的儲存 page 的 ViewState. 這個方法可覆寫。如果重寫的話,注意這裡由于 asp.net 的 bug, 需要手工設定一下 __VIEWSTATE,哪怕是空值。

接着是 Render 方法。它遞歸的調用到每個子控件,真正的繪制各自的 html, 發送到浏覽器。在一些頁面模闆方案中,常常在這裡添加通用的 header 和 footer. 而不用使用伺服器控件。 注意在這裡能作的更改必須是純的 html. 因為這時候控件都已經繪制完了。

最後是 OnUnload 方法。它調用了 Dispose 方法。這個方法可以用來清理頁面中使用的非托管資源。特别是類似于關閉打開的檔案或資料庫連接配接等。該方法隻有當頁面已經被發送到用戶端浏覽器後才發生。是以它隻能對服務端的對象起作用。是以他不能在 page 的 trace 中被顯示。

上面就是 page 的生命循環。每次有一個新的請求時,以上過程就重複一次。

Method

PostBack

Controls

Constructor

Always

All

AddParsedSubObject

DeterminePostBackMode

Page

OnInit

LoadPageStateFromPersistenceMedium

LoadViewState

ProcessPostData1

OnLoad

ProcessPostData2

RaiseChangedEvents

RaisePostBackEvent

OnPreRender

SaveViewState

SavePageStateToPersistenceMedium

Render

OnUnload

-----------------------------------------------------------------

我做的小程式們

【推薦】Web版短信管理平台源碼

WinForm版短信管理平台源碼

移動短信程式源碼Win服務版(CMPP3.0/CMPP2.0協定)

移動物聯網卡短信源碼(CMPP3.0協定,支援MsSql/MySql資料庫)

C#實作聯通短信Sgip協定程式源碼

C#實作電信短信SMGP協定程式源碼

C#實作移動短信CMPP服務端程式源碼