ASP.NET頁面生存周期關鍵事件及執(zhí)行步驟
ASP.NET頁面生存周期介紹
一旦完全確定 HTTP 頁面處理程序類,ASP.NET 運行時就調用該處理程序的 ProcessRequest 方法以處理請求。通常情況下,無需更改此方法的實現(xiàn)方式,因為它是由 Page 類提供的。
此實現(xiàn)方法一開始就調用 FrameworkInitialize 方法,以此建立頁面的控件樹。此方法是 TemplateControl 類(Page 類本身就是從該類派生出來的)的一個受保護的虛擬成員。任何針對 .aspx 資源而動態(tài)生成的處理程序都重寫 FrameworkInitialize。在此方法中,該頁面的完整控件樹得以構建。
接下來,ProcessRequest 使該頁面經(jīng)歷若干階段:初始化,加載視圖狀態(tài)信息和回發(fā)數(shù)據(jù),加載頁面的用戶代碼并執(zhí)行回發(fā)服務器端事件。隨后,該頁面進入呈現(xiàn)模式:收集更新后的視圖狀態(tài);生成 HTML 代碼然后將其發(fā)送到輸出控制臺。最后,卸載頁面,并認為已完成對該請求的處理。
在各個階段中,頁面都會激發(fā)一些 Web 控件和用戶定義的代碼所能截獲并處理的事件。其中的一些事件是嵌入式控件專用的,因而并不能在 .aspx 代碼級進行處理。
如果頁面想要處理某個事件,它應該顯式地注冊相應的處理程序。然而,為了向后兼容早期的 Visual Basic 編程風格,ASP.NET 也支持一種隱式的事件掛起形式。在默認情況下,頁面將嘗試把特定的方法名與事件匹配起來;如果找到匹配的方法,就認為該方法是該事件的處理程序。ASP.NET 提供了六個方法名的特定識別。它們是 Page_Init、Page_Load、Page_DataBind、Page_PreRender 和 Page_Unload。這些方法被當作是 Page 類所提供的相應事件的處理程序。HTTP 運行時將自動把這些方法與頁面事件綁定起來,這樣一來,開發(fā)人員就不必編寫所需的粘接代碼。例如,名為 Page_Load 的方法與頁面的 Load 事件綁定,就像已編寫以下代碼一樣。
- this.Load += new EventHandler(this.Page_Load);
這種自動識別特殊名稱的功能由 @Page 指令的 AutoEventWireup 屬性控制。如果將該屬性設置為 false,則任何想要處理某個事件的應用程序都需顯式地連接到該頁面事件。如果頁面不使用自動事件關聯(lián)功能,就不必進行額外的操作以匹配各名稱和事件,從而其性能也稍有提升。應該注意的是,所有的 Microsoft Visual Studio.NET 項目在創(chuàng)建時都禁用了 AutoEventWireup 屬性。然而,此屬性的默認設置為 true,意味著諸如 Page_Load 等方法會被識別并被綁定到相關的事件。
頁面的執(zhí)行過程包括下面表格中所列的一系列階段,并以具有一些應用程序級事件和/或受保護且可重寫的方法為特征。
表格 1. ASP.NET頁面生存周期中的關鍵事件
階段 |
頁面事件 |
可重寫方法 |
---|---|---|
頁面初始化 |
Init |
|
加載視圖狀態(tài) |
LoadViewState | |
處理回發(fā)數(shù)據(jù) |
實現(xiàn) IPostBackDataHandler 接口的任何控件中的 LoadPostData 方法 | |
加載頁面 |
Load |
|
回發(fā)更改通知 |
實現(xiàn) IPostBackDataHandler 接口的任何控件中的 RaisePostDataChangedEvent 方法 | |
處理回發(fā)事件 |
控件所定義的任何回發(fā)事件 |
實現(xiàn)了 IPostBackEventHandler 接口的任何控件的 RaisePostBackEvent 方法 |
頁面呈現(xiàn)前階段 |
PreRender |
|
保存視圖狀態(tài) |
SaveViewState | |
呈現(xiàn)頁面 |
Render | |
卸載頁面 |
Unload |
在頁面級上,以上所列的某些階段是不可見的,并僅影響服務器控件編寫者和那些湊巧要創(chuàng)建從 Page 派生的類的開發(fā)人員。頁面向外界發(fā)送的活動信號僅包括 Init、Load、PreRender、Unload 以及嵌入式控件所定義的所有回發(fā)事件。
ASP.NET頁面生存周期:執(zhí)行的各個階段
頁面生存周期中的第一個階段是初始化。這一階段的標志就是 Init 事件,在成功創(chuàng)建頁面的控件樹后,對應用程序激發(fā)這個事件。換而言之,當 Init 事件發(fā)生時,在 .aspx 源文件中靜態(tài)聲明的所有控件都已實例化并取其默認值??丶蓲炱?Init 事件,以便初始化在傳入的 Web 請求的生存周期中所需的任何設置。例如,此時控件可以加載外部模板文件或設置各個事件的處理程序。應該注意到,這時還沒有視圖狀態(tài)信息可供使用。
在初始化之后,頁面框架立即加載該頁面的視圖狀態(tài)。所謂視圖狀態(tài)就是一些名稱/值對的集合,控件和頁面本身可將那些對所有 Web 請求都必須始終有效的任何信息存儲在其中。視圖狀態(tài)表示頁面的調用上下文。一般情況下,其中包含上次在服務器中處理該頁面時各控件的狀態(tài)。首次在會話中請求頁面時,視圖狀態(tài)為空。在默認情況下,視圖狀態(tài)被存儲在一個隱藏字段中,而該字段是自行添加到頁面中的。該字段名稱為 __VIEWSTATE。通過重寫 LoadViewState 方法(Control 類的一個受保護且可重寫的方法)組件開發(fā)人員可控制如何還原視圖狀態(tài)以及如何將其內容映射到內部狀態(tài)。
有些方法(如 LoadPageStateFromPersistenceMedium 及其相對的 SavePageStateToPersistenceMedium)可用于將視圖狀態(tài)加載并保存到別的存儲介質(例如會話、數(shù)據(jù)庫或服務器端的文件)中。與 LoadViewState 不同,上述方法僅在派生自 Page 的各個類中才可使用。
一旦還原了視圖狀態(tài),頁面樹中的各個控件的狀態(tài)就與瀏覽器上次呈現(xiàn)該頁面時這些控件所處的狀態(tài)相同。下一步包括更新這些控件的狀態(tài)以加入客戶端的變更?;匕l(fā)數(shù)據(jù)處理階段使各個控件有機會更新其狀態(tài),以便準確地反映相應的 HTML 元素在客戶端的狀態(tài)。例如,一個服務器 TextBox 控件對應的 HTML 元素是 <input type=text>。在回發(fā)數(shù)據(jù)階段,TextBox 控件將檢索 <input> 標記的當前值并用它刷新其內部狀態(tài)。每個控件負責從已發(fā)送的數(shù)據(jù)中提取相應值,并更新其某些屬性。TextBox 控件將更新其 Text 屬性,而 CheckBox 控件將刷新其 Checked 屬性。服務器控件和 HTML 元素之間的匹配關系由二者的 ID 確定。
在回發(fā)數(shù)據(jù)處理階段結束時,頁面中的所有控件都根據(jù)客戶端上所輸入的更改來更新原先的狀態(tài)。此時,對頁面激發(fā) Load 事件。
如果在處理兩個不同的請求時某個敏感的屬性被修改,則頁面上可能有些控件需要完成某些任務。例如,如果在客戶端修改了某個文本框控件的文本,則該控件激發(fā) TextChanged 事件。如果利用來自客戶端的值對該控件的一個或多個屬性進行修改,每個控件可以決定激發(fā)一個適當?shù)氖录?。對控件而言,如果這些更改是至關重要的,則這些控件實現(xiàn) IPostBackDataHandler 接口,在 Load 事件之后立即調用該接口的 LoadPostData 方法。通過編寫 LoadPostData 方法的代碼,一個控件可以確認自最近一次請求以來是否發(fā)生了任何關鍵的更改,并激發(fā)自己的更改事件。
頁面生存周期內的關鍵事件就是:它被調用來執(zhí)行與客戶端上所激發(fā)的某個事件相關聯(lián)的服務器端代碼。當用戶單擊某個按鈕時,頁面回發(fā)數(shù)據(jù)。已發(fā)送值的集合中包含該按鈕(該按鈕啟動整個操作)的 ID。如果已知該控件實現(xiàn)了 IPostBackEventHandler 接口(按鈕和鏈接按鈕將實現(xiàn)此接口),則頁面框架調用 RaisePostBackEvent 方法。此方法所進行的操作取決于相應控件的類型。對于按鈕和鏈接按鈕,此方法查找 Click 事件處理程序并運行相關的委托。
在處理回發(fā)事件后,頁面就準備進行呈現(xiàn)。這一階段的標志是 PreRender 事件。各個控件可利用這個很好的時機,以便執(zhí)行任何需要在保存視圖狀態(tài)和呈現(xiàn)輸出結果的前一刻完成的最后一些更新操作。下一個狀態(tài)為 SaveViewState,在這一狀態(tài)中所有控件以及頁面本身可以刷新自己的 ViewState 集合的內容。所得到的視圖狀態(tài)隨后得以序列化、進行哈希運算、進行 Base64 編碼并關聯(lián)到 __VIEWSTATE 隱藏字段。
通過重寫 Render 方法,即可更改各個控件的呈現(xiàn)機制。該方法獲取一個 HTML 編寫器對象,并使用該對象聚集所有將針對該控件生成的 HTML 文本。Page 類的 Render 方法的默認實現(xiàn)方式包括對所有成員控件的遞歸調用。對于每個控件,頁面都調用 Render 方法并將 HTML 輸出放入高速緩存。
一個頁面的最后生存標志就是 Unload 事件,該事件在頁面對象被解除之前發(fā)生。在此事件中,您應該釋放可能占用的任何關鍵資源(例如,文件、圖形對象、數(shù)據(jù)庫連接)。
終于,在此事件之后,瀏覽器收到 HTTP 響應數(shù)據(jù)包并顯示頁面。
【編輯推薦】