摘要:了解為 ASP.NET Web 頁面建立的事件模型,以及 Web 頁面轉變為 HTML 過程中的各個階段。ASP.NET HTTP 運行時負責管理對象管道,這些對象首先將請求的 URL 轉換成 Page 類的具體實例,然後再將這些實例轉換成純 HTML 文本。本文將探討那些作為頁面生命周期標志的事件,以及控件和頁面編寫者如何干預並改變標准行為。
簡介
對由 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);