ASP.NET頁面事件執行過程(完整版)
http://www.cnblogs.com/dachie/archive/2010/05/14/1735526.html
ASP.NET 母版頁和內容頁中的事件
母版頁和內容頁都可以包含控制元件的事件處理程式。對於控制元件而言,事件是在本地處理的,即內容頁中的控制元件在內容頁中引發事件,母版頁中的控制元件在母版頁中引發事件。控制元件事件不會從內容頁傳送到母版頁。同樣,也不能在內容頁中處理來自母版頁控制元件的事件。
在某些情況下,內容頁和母版頁中會引發相同的事件。例如,兩者都引發 Init 和 Load 事件。引發事件的一般規則是初始化事件從最裡面的控制元件向最外面的控制元件引發,所有其他事件則從最外面的控制元件向最裡面的控制元件引發。請記住,母版頁會合併到內容頁中並被視為內容頁中的一個控制元件,這一點十分有用。
下面是母版頁與內容頁合併後事件的發生順序:
- 母版頁控制元件 Init 事件。
- 內容控制元件 Init 事件。
- 母版頁 Init 事件。
- 內容頁 Init 事件。
- 內容頁 Load 事件。
- 母版頁 Load 事件。
- 內容控制元件 Load 事件。
- 內容頁 PreRender 事件。
- 母版頁 PreRender 事件。
- 母版頁控制元件 PreRender 事件。
- 內容控制元件 PreRender 事件。
母版頁和內容頁中的事件順序對於頁面開發人員並不重要。但是,如果您建立的事件處理程式取決於某些事件的可用性,那麼您將發現,瞭解母版頁和內容頁中的事件順序很有幫助。
Page 執行中將按照如下順序啟用事件:
Page.PreInit
Page.Init
Page.InitComplite
Page.PreLoad
Page.Load
Page.LoadComplete
Page.PreRender
Page.PreRenderComplete
如果頁面從另一個頁面繼承,如BasePage:System.Web.UI.Page,在BasePage中做了一些擴充套件,如許可權檢查,而其他頁面從BasePage繼承,則BasePage和最終Page的事件啟用順序是:
UI.PreInit
Page.PreInit
UI.Init
Page.Init
UI.InitComplite
Page.InitComplite
UI.PreLoad
Page.PreLoad
UI.Load
Page.Load
UI.LoadComplete
Page.LoadComplete
UI.PreRender
Page.PreRender
UI.PreRenderComplete
Page.PreRenderComplete
如果使用了MasterPage,則MasterPage中的事件和ContentPage中的事件按照下面順序啟用:
ContentPage.PreInit
Master.Init
ContentPage.Init
ContentPage.InitComplite
ContentPage.PreLoad
ContentPage.Load
Master.Load
ContentPage.LoadComplete
ContentPage.PreRender
Master.PreRender
ContentPage.PreRenderComplete
更進一步,如果ContentPage繼承BasePage,那麼,各事件的執行順序將變成:
UI.PreInit
ContentPage.PreInit
Master.Init
UI.Init
ContentPage.Init
UI.InitComplite
ContentPage.InitComplite
UI.PreLoad
ContentPage.PreLoad
UI.Load
ContentPage.Load
Master.Load
UI.LoadComplete
ContentPage.LoadComplete
UI.PreRender
ContentPage.PreRender
Master.PreRender
UI.PreRenderComplete
ContentPage.PreRenderComplete
瀏覽下來發現並不是我現在所學的asp.net 1.1,估計應該是asp.net 2.0,
不過也沒有關係,這讓我知道了他們有繼承時載入的順序。
即:先載入繼承頁的,再載入自己的,如果繼承頁有繼承則先載入繼承頁的繼承。
其實是個很簡單的內容。順便寫下Page事件(不知道1.1是不是就這些)
事件處理器名稱 |
發生時間 |
Page_Init |
在Web窗體的檢視狀態載入伺服器控制元件並對其初始化。 這是web窗體生命週期的第一步 |
Page_Load |
在Page物件上載入伺服器控制元件。由於此時檢視狀態資訊是可以使用的, 因此載這裡可以用程式碼來改變空間的設定或者載頁面上顯示文字。 |
Page_PreRender |
應用程式將要呈現Page物件 |
Page_Unload |
頁面從記憶體中解除安裝 |
Page_Error |
發生未處理的異常 |
Page_AbortTransaction |
事務處理被終止 |
Page_CommitTransaction |
事務處理被接受 |
Page_DataBinding |
把頁面上的伺服器空間和資料來源繫結載一起 |
Page_Disposed |
Page物件從記憶體中釋放掉。這是Page物件生命週期中的最後一個事件 |
Init,Load,PreRender
事件執行順序:
1)控制元件的Init事件
2)控制元件所在頁面的Init事件
3)控制元件所在頁面的Load事件
4)控制元件的Load事件
5)控制元件所在頁面的PreRender事件
6)控制元件的PreRender事件
規律:
1)Init事件從最裡面的控制元件(包括使用者控制元件及普通控制元件)向最外面的控制元件(頁面)引發,Load及PreRender等其他事件從最外面的控制元件向最裡面的控制元件引發;
2)控制元件之間相同事件的執行順序依控制元件在頁面的位置按從左到右,從上到下的先後順序執行。
注意:
1)切記使用者控制元件也被視為頁面中的一個控制元件;
2)把使用者控制元件作為單獨的一個特殊頁面來看,它本身及其所包含的控制元件同樣遵守相同的規律;
3)有時在客戶端程式(如javascript)中會用到客戶端body對像的onload事件,注意這個客戶端事件是最後執行,即在伺服器端所有事件執行完後才執行。
測試環境:
Windows2000 Pro+IIS5.0+Dotnet Framework1.1
===================================================================================
轉載一篇關於頁面物件模型的文章,說得比較詳細,有助理解。沒事的時候就多看兩遍,慢慢體會:)。
ASP.NET 頁面物件模型 |
Dino Esposito 2003 年 8 月 |
適用於:
Microsoft® ASP.NET
摘要 : 瞭解為 ASP.NET Web 頁面建立的事件模型,以及 Web 頁面轉變為 HTML 過程中的各個階段。ASP.NET HTTP 執行時負責管理物件管道,這些物件首先將請求的 URL 轉換成 Page 類的具體例項,然後再將這些例項轉換成純 HTML 文字。本文將探討那些作為頁面生命週期標誌的事件,以及控制元件和頁面編寫者如何幹預並改變標準行為。(本文包含一些指向英文站點的連結。)
目錄
簡介
真正的 Page 類
頁面的生命週期
執行的各個階段
小結
簡介
對 由 Microsoft® Internet 資訊服務 (IIS) 處理的 Microsoft® ASP.NET 頁面的每個請求都會被移交到 ASP.NET HTTP 管道。HTTP 管道由一系列託管物件組成,這些託管物件按順序處理請求,並將 URL 轉換為純 HTML 文字。HTTP 管道的入口是 HttpRuntime 類。ASP.NET 結構為輔助程序中的每個 AppDomain 建立一個此類的例項。(請注意,輔助程序為每個當前正在執行的 ASP.NET 應用程式維護一個特定的 AppDomain。)
HttpRuntime 類從內部池中獲取 HttpApplication 物件,並安排此物件來處理請求。HTTP 應用程式管理器完成的主要任務就是找到將真正處理請求的類。當請求 .aspx 資源時,處理程式就是頁面處理程式,即從 Page 繼承的類的例項。資源型別和處理程式型別之間的關聯關係儲存在應用程式的配置檔案中。更確切地說,預設的對映集是在 machine.config 檔案的 <httpHandlers> 部分定義的。但是,應用程式可以在本地的 web.config 檔案中自定義自己的 HTTP 處理程式列表。以下這一行程式碼就是用來為 .aspx 資源定義 HTTP 處理程式的。
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>
副檔名可以與處理程式類相關聯,並且更多是與處理程式工廠類相關聯。在所有情況下,負責處理請求的 HttpApplication 物件都會獲得一個實現 IHttpHandler 介面的物件。如果根據 HTTP 處理程式來解析關聯的資源/類,則返回的類將直接實現介面。如果資源被繫結到處理程式工廠,則還需要額外的步驟。處理程式工廠類實現 IHttpHandlerFactory 介面,此介面的 GetHandler 方法將返回一個基於 IHttpHandler 的物件。
HTTP 執行時是如何結束這個迴圈並處理頁面請求的?ProcessRequest 方法在 IHttpHandler 介面中非常重要。通過對代表被請求頁面的物件呼叫此方法,ASP.NET 結構會啟動將生成瀏覽器輸出的程序。
真正的 Page 類
特 定頁面的 HTTP 處理程式型別取決於 URL。首次呼叫 URL 時,將構建一個新的類,這個類被動態編譯為一個程式集。檢查 .aspx 資源的分析程序的結果是類的原始碼。該類被定義為名稱空間 ASP 的組成部分,並且被賦予了一個模擬原始 URL 的名稱。例如,如果 URL 的終點是 page.aspx,則類的名稱就是 ASP.Page_aspx 。不過,類的名稱可以通過程式設計方式來控制,方法是在 @Page 指令中設定 ClassName 屬性。
HTTP 處理程式的基類是 Page 。這個類定義了由所有頁面處理程式共享的方法和屬性的最小集合。Page 類實現 IHttpHandler 介面。
在很多情況下,實際處理程式的基類並不是 Page , 而是其他的類。例如,如果使用了程式碼分離,就會出現這種情況。程式碼分離是一項開發技術,它可以將頁面所需的程式碼隔離到單獨的 C# 和 Microsoft Visual Basic® .NET 類中。頁面的程式碼是一組事件處理程式和輔助方法,這些處理程式和方法真正決定了頁面的行為。可以使用 <script runat=server> 標記對此程式碼進行內聯定義,或者將其放置在外部類(程式碼分離類)中。程式碼分離類是從 Page 繼承並使用額外的方法的類,被指定用作 HTTP 處理程式的基類。
還有一種情況,HTTP 處理程式也不是基於 Page 的,即在應用程式配置檔案的 <pages> 部分中,包含了 PageBaseType 屬性的重新定義。
<pages PageBaseType="Classes.MyPage, mypage" />
PageBaseType 屬性指明包含頁面處理程式的基類的型別和程式集。從 Page 匯出的這個類可以自動賦予處理程式擴充套件的自定義方法和屬性集。
頁面的生命週期
完全識別 HTTP 頁面處理程式類後,ASP.NET 執行時將呼叫處理程式的 ProcessRequest 方法來處理請求。通常情況下,無需更改此方法的實現,因為它是由 Page 類提供的。
此實現將從呼叫為頁面構建控制元件樹的 FrameworkInitialize 方法開始。FrameworkInitialize 方法是 TemplateControl 類(Page 本身從此類匯出)的一個受保護的虛擬成員。所有為 .aspx 資源動態生成的處理程式都將覆蓋 FrameworkInitialize 。在此方法中,構建了頁面的整個控制元件樹。
接下來,ProcessRequest 使頁面經歷了各個階段:初始化、載入檢視狀態資訊和回發資料、載入頁面的使用者程式碼以及執行回發伺服器端事件。之後,頁面進入顯示模式:收集更新的檢視狀態,生成 HTML 程式碼並隨後將程式碼傳送到輸出控制檯。最後,解除安裝頁面,並認為請求處理完畢。
在各個階段中,頁面會觸發少數幾個事件,這些事件可以由 Web 控制元件和使用者定義的程式碼擷取並進行處理。其中的一些事件是嵌入式控制元件專用的,因此無法在 .aspx 程式碼級進行處理。
要 處理特定事件的頁面應該明確註冊一個適合的處理程式。不過,為了向後相容早期的 Visual Basic 程式設計風格,ASP.NET 也支援隱式事件掛鉤的形式。預設情況下,頁面會嘗試將特定的方法名稱與事件相匹配,如果實現匹配,則認為此方法就是匹配事件的處理程式。ASP.NET 提供了六種方法名稱的特定識別,它們是 Page_Init 、Page_Load 、Page_DataBind 、Page_PreRender 和 Page_Unload 。這些方法被認為是由 Page 類提供的相應事件的處理程式。HTTP 執行時會自動將這些方法繫結到頁面事件,這樣,開發人員就不必再編寫所需的粘接程式碼了。例如,如果命名為 Page_Load 的方法繫結到頁面的 Load 事件,則可省去以下程式碼。
this.Load += new EventHandler(this.Page_Load);
對特定名稱的自動識別是由 @Page 指令的 AutoEventWireup 屬性控制的。如果該屬性設定為 false,則要處理事件的所有應用程式都需要明確連線到頁面事件。不使用自動繫結事件的頁面效能會稍好一些,因為不需要額外匹配名稱與事件。請注意,所有 Microsoft Visual Studio® .NET 專案都是在禁用 AutoEventWireup 屬性的情況下建立的。但是,該屬性的預設設定是 true,即 Page_Load 等方法會被識別,並被繫結到相關聯的事件。
下表中按順序列出了頁面的執行包括的幾個階段,執行的標誌是一些應用程式級的事件和/或受保護並可覆蓋的方法。
表 1:ASP.NET 頁面生命中的關鍵事件
階段 |
頁面事件 |
可覆蓋的方法 |
頁面初始化 |
Init |
|
載入檢視狀態 |
LoadViewState |
|
處理回發資料 |
任意實現 IPostBackDataHandler 介面的控制元件中的 LoadPostData 方法 |
|
載入頁面 |
Load |
|
回發更改通知 |
任意實現 IPostBackDataHandler 介面的控制元件中的 RaisePostDataChangedEvent 方法 |
|
處理回發事件 |
由控制元件定義的任意回發事件 |
任意實現 IPostBackDataHandler 介面的控制元件中的 RaisePostBackEvent 方法 |
頁面顯示前階段 |
PreRender |
|
儲存檢視狀態 |
SaveViewState |
|
顯示頁面 |
Render |
|
解除安裝頁面 |
Unload |
以上所列的階段中有些在頁面級是不可見的,並且僅對伺服器控制元件的編寫者和要建立從 Page 匯出的類的開發人員有意義。Init 、Load 、PreRender 、Unload ,再加上由嵌入式控制元件定義的所有回發事件,就構成了向外傳送頁面的各個階段標記。
執行的各個階段
頁面生命週期中的第一個階段是初始化。這個階段的標誌是 Init 事件。在成功建立頁面的控制元件樹後,將對應用程式觸發此事件。換句話說,當 Init 事件發生時,.aspx 原始檔中靜態宣告的所有控制元件都已例項化並採用各自的預設值。控制元件可以擷取 Init 事件以初始化在傳入的 Web 請求的生命週期內所需的所有設定。例如,這時控制元件可以載入外部模板檔案或設定事件的處理程式。請注意,這時檢視狀態資訊尚不可用。
初 始化之後,頁面框架將載入頁面的檢視狀態。檢視狀態是名稱/值對的集合,在此集合中,控制元件和頁面本身儲存了對所有 Web 請求都必須始終有效的全部資訊。檢視狀態代表了頁面的呼叫上下文。通常,它包含上次在伺服器上處理頁面時控制元件的狀態。首次在會話中請求頁面時,檢視狀態為 空。預設情況下,檢視狀態儲存在靜默新增到頁面的隱藏欄位中,該欄位的名稱是 __VIEWSTATE 。通過覆蓋 LoadViewState 方法(Control 類的受保護、可覆蓋方法),元件開發人員可以控制檢視狀態的儲存方式以及檢視狀態的內容對映到內部狀態的方式。
有些方法(如 LoadPageStateFromPersistenceMedium 以及其對應的 SavePageStateToPersistenceMedium ),可以用來將檢視狀態載入並儲存到其他儲存介質(例如會話、資料庫或伺服器端檔案)中。與 LoadViewState 不同,上述方法只能在從 Page 匯出的類中使用。
儲存檢視狀態之後,頁面樹中控制元件的狀態與頁面最後一次顯示在瀏覽器中的狀態相同。下一步是更新它們的狀態以加入客戶端的更改。處理回發資料階段使控制元件有機會更新其狀態,從而準確反映客戶端相應的 HTML 元素的狀態。例如,伺服器的 TextBox 控制元件對應的 HTML 元素是 <input type=text> 。在回發資料階段,TextBox 控制元件將檢索 <input> 標記的當前值,並使用該值來重新整理自己內部的狀態。每個控制元件都要從回發的資料中提取值並更新自己的部分屬性。TextBox 控制元件將更新它的 Text 屬性,而 CheckBox 控制元件將重新整理它的 Checked 屬性。伺服器控制元件和 HTML 元素的對應關係可以通過二者的 ID 找到。
在處理回發資料階段的最後,頁面中的所有控制元件的狀態都將使用客戶端輸入的更改來更新前一狀態。這時,將對頁面觸發 Load 事件。
頁面中可能會有一些控制元件,當其某個敏感屬性在兩個不同的請求中被修改時,需要完成特定的任務。例如,如果 TextBox 控制元件的文字在客戶端被修改,則此控制元件將觸發 TextChanged 事件。每個控制元件在其一個或多個屬性被修改為客戶端輸入的值時都可以決定觸發相應的事件。對於這些更改對其非常關鍵的控制元件,控制元件實現 IPostBackDataHandler 介面,此介面的 LoadPostData 方法是在 Load 事件後立即呼叫的。通過對 LoadPostData 方法進行編碼,控制元件將驗證自上次請求後是否發生了關鍵更改,並觸發自己的更改事件。
頁面生命週期中的關鍵事件是被呼叫以執行伺服器端程式碼的事件,此程式碼與客戶端觸發的事件相關聯。當用戶單擊按鈕時,將回發頁面。回發值的集合中包括啟動整個操作的按鈕的 ID。如果控制元件實現 IPostBackEventHandler 介面(如按鈕和連結按鈕),頁面框架將呼叫 RaisePostBackEvent 方法。此方法的行為取決於控制元件的型別。就按鈕和連結按鈕而言,此方法將查詢 Click 事件處理程式並執行相關的委託。
處理完回發事件之後,頁面就可以顯示了。這個階段的標誌是 PreRender 事件。控制元件可以利用這段時間來執行那些需要在儲存檢視狀態和顯示輸出的前一刻執行的更新操作。下一個狀態是 SaveViewState ,在此狀態中,所有控制元件和頁面本身都將更新自己 ViewState 集合的內容。然後,將得到序列化、雜湊、Base64 編碼的檢視狀態,而且此檢視狀態與隱藏欄位 __VIEWSTATE 相關聯。
通過覆蓋 Render 方法可以改變各個控制元件的顯示機制。此方法接受 HTML 書寫器物件,並使用此物件來積累所有要為控制元件生成的 HTML 文字。Page 類的 Render 方法的預設實現包括對所有成員控制元件的遞迴呼叫。對於每個控制元件,頁面都將呼叫 Render 方法,並快取 HTML 輸出。
頁面生命中的最後一個標誌是 Unload 事件,在頁面物件消除之前發生。在此事件中,您應該釋放所有可能佔用的關鍵資源(例如檔案、圖形物件、資料庫連線等)。
在此事件之後,也就是最後,瀏覽器接收 HTTP 響應資料包並顯示頁面。
小結
ASP.NET 頁面物件模型因其事件機制而顯得格外新穎獨特。Web 頁面由控制元件組成,這些控制元件既可以產生豐富的基於 HTML 的使用者介面,又可以通過事件與使用者互動。以前,在 Web 應用程式的上下文中設定事件模型是件有挑戰性的工作。可我們驚奇的看到,客戶端生成的事件可以由伺服器端的程式碼來解決,而且只進行一些相應的修改後,此過 程仍可以輸出相同的 HTML 頁面。
掌握這個模型對於瞭解頁面生命週期的各個階段,以及頁面物件如何被 HTTP 執行時例項化並使用是非常重要的。
作者:達奇 本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。