ASP.NET 頁面物件模型

來源:互聯網
上載者:User
http://www.microsoft.com/china/msdn/library/webservices/asp.net/BedrockAspNet.mspx

ASP.NET Web 頁面生命曆程中的一天

Dino Esposito Wintellect

2003 年 8 月

適用於: Microsoft ASP.NET

摘要:瞭解圍繞 ASP.NET Web 頁構建的事件模型,以及一個 Web 頁面在其轉變為 HTML 的曆程中的各個階段。ASP.NET HTTP 運行時控制對象管線,對象管線首先將所請求的 URL 轉換為一個頁面類的活動執行個體,然後將其轉換為普通 HTML 文本。本文將探討一個頁面的生存周期中的各個特徵事件,並瞭解控制項和頁面編寫者如何介入其中以改變其標準行為。(6 頁列印頁)

本頁內容
簡介
真正的 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"/>

副檔名可關聯到一個處理常式類,或者更普遍地關聯到一個處理常式工廠 (handler factory) 類。在所有情況下,負責處理請求的 HttpApplication 對象都會獲得一個實現 IHttpHandler 介面的對象。如果根據 HTTP 處理常式來解析關聯資源/類,那麼所返回的類將直接實現該介面。如果資源綁定到處理常式工廠,則需要另外一個步驟。處理常式工廠類實現 IHttpHandlerFactory 介面,而該介面的 GetHandler 方法返回一個基於 IHttpHandler 的對象。

HTTP 運行時如何能完成整個迴圈並處理頁面請求呢?IHttpHandler 介面特別提供了 ProcessRequest 方法。通過對代表所請求頁面的對象調用此方法,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 處理常式的基類。

還有一種情況,即當應用程式設定檔的 <pages> 部分中重新定義了 PageBaseType 屬性時,HTTP 處理常式也不是基於 Page 的。

<pages PageBaseType="Classes.MyPage, mypage" />

PageBaseType 屬性指出了包含頁面處理常式的基類的類型以及程式集。派生自 Page 的這個類可自動給處理常式賦予一組自訂和擴充的方法和屬性。

返回頁首

頁面生存周期

一旦完全確定 HTTP 頁面處理常式類,ASP.NET 運行時就調用該處理常式的 ProcessRequest 方法以處理請求。通常情況下,無需更改此方法的實現方式,因為它是由 Page 類提供的。

此實現方法一開始就調用 FrameworkInitialize 方法,以此建立頁面的控制項樹。此方法是 TemplateControl 類(Page 類本身就是從該類派生出來的)的一個受保護的虛擬成員。任何針對 .aspx 資源而動態產生的處理常式都重寫 FrameworkInitialize。在此方法中,該頁面的完整控制項樹得以構建。

接下來,ProcessRequest 使該頁面經曆若干階段:初始化,載入檢視狀態資訊和回傳資料,載入頁面的使用者代碼並執行回傳伺服器端事件。隨後,該頁面進入呈現模式:收集更新後的檢視狀態;產生 HTML 程式碼然後將其發送到輸出控制台。最後,卸載頁面,並認為已完成對該請求的處理。

在各個階段中,頁面都會激發一些 Web 控制項和使用者定義的代碼所能截獲並處理的事件。其中的一些事件是嵌入式控制項專用的,因而並不能在 .aspx 代碼級進行處理。

如果頁面想要處理某個事件,它應該顯式地註冊相應的處理常式。然而,為了向後相容早期的 Visual Basic 編程風格,ASP.NET 也支援一種隱式的事件掛起形式。在預設情況下,頁面將嘗試把特定的方法名與事件匹配起來;如果找到匹配的方法,就認為該方法是該事件的處理常式。ASP.NET 提供了六個方法名的特定識別。它們是 Page_InitPage_LoadPage_DataBindPage_PreRenderPage_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 方法

處理回傳事件

控制項所定義的任何回傳事件

實現了 IPostBackEventHandler 介面的任何控制項的 RaisePostBackEvent 方法

頁面呈現前階段

PreRender

儲存檢視狀態

SaveViewState

呈現頁面

Render

卸載頁面

Unload

在頁面級上,以上所列的某些階段是不可見的,並僅影響伺服器控制項編寫者和那些湊巧要建立從 Page 派生的類的開發人員。頁面向外界發送的活動訊號僅包括 InitLoadPreRenderUnload 以及嵌入式控制項所定義的所有回傳事件。

返回頁首

執行的各個階段

頁面生存周期中的第一個階段是初始化。這一階段的標誌就是 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 事件。

如果在處理兩個不同的請求時某個敏感的屬性被修改,則頁面上可能有些控制項需要完成某些任務。例如,如果在用戶端修改了某個文字框控制項的文本,則該控制項激發 TextChanged 事件。如果利用來自用戶端的值對該控制項的一個或多個屬性進行修改,每個控制項可以決定激發一個適當的事件。對控制項而言,如果這些更改是至關重要的,則這些控制項實現 IPostBackDataHandler 介面,在 Load 事件之後立即調用該介面的 LoadPostData 方法。通過編寫 LoadPostData 方法的代碼,一個控制項可以確認自最近一次請求以來是否發生了任何關鍵的更改,並激發自己的變更事件。

頁面生存周期內的關鍵事件就是:它被調用來執行與用戶端上所激發的某個事件相關聯的伺服器端代碼。當使用者單擊某個按鈕時,頁面回傳資料。已發送值的集合中包含該按鈕(該按鈕啟動整個操作)的 ID。如果已知該控制項實現了 IPostBackEventHandler 介面(按鈕和連結按鈕將實現此介面),則頁面架構調用 RaisePostBackEvent 方法。此方法所進行的操作取決於相應控制項的類型。對於按鈕和連結按鈕,此方法尋找 Click 事件處理常式並運行相關的委託。

在處理回傳事件後,頁面就準備進行呈現。這一階段的標誌是 PreRender 事件。各個控制項可利用這個很好的時機,以便執行任何需要在儲存檢視狀態和呈現輸出結果的前一刻完成的最後一些更新操作。下一個狀態為 SaveViewState,在這一狀態中所有控制項以及頁面本身可以重新整理自己的 ViewState 集合的內容。所得到的檢視狀態隨後得以序列化、進行雜湊運算、進行 Base 64 編碼並關聯到 __VIEWSTATE 隱藏欄位。

通過重寫 Render 方法,即可更改各個控制項的呈現機制。該方法擷取一個 HTML 編寫器對象,並使用該對象聚集所有將針對該控制項產生的 HTML 文本。Page 類的 Render 方法的預設實現方式包括對所有成員控制項的遞迴調用。對於每個控制項,頁面都調用 Render 方法並將 HTML 輸出放入快取。

一個頁面的最後生存標誌就是 Unload 事件,該事件在頁面對象被解除之前發生。在此事件中,您應該釋放可能佔用的任何關鍵資源(例如,檔案、繪圖物件、資料庫連接)。

終於,在此事件之後,瀏覽器收到 HTTP 響應資料包並顯示頁面。

返回頁首

小結

ASP.NET 頁面物件模型由於使用了事件機制而特別具有創新意義。Web 頁面由各種控制項構成,這些控制項既形成一個豐富的基於 HTML 的使用者介面,又通過事件與使用者進行互動。在 Web 應用程式的上下文中建立事件模型是一項極具挑戰性的任務。令人驚奇的是,利用伺服器端代碼可以處理用戶端產生的事件,而且這種方法的輸出看起來與 HTML 頁面相同,只是經過了適當的修改。

要掌握這個模型,重要的一點是要理解頁面生存周期中的不同階段,以及 HTTP 運行時如何執行個體化和使用頁面對象。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.