天天看點

記不住ASP.NET頁面生命周期的苦惱

對于ASP.NET開發者,了解ASP.NET的頁面生命周期是非常重要的。主要是為了搞明白在哪裡放置特定的方法和在何時設定各種頁面屬性。但是記憶和了解頁面生命周期裡提供的事件處理方法(method)非常困難。網際網路上有很多關于頁面生命周期内部機制的文章,是以本文隻準備簡單覆寫技術的基礎部分,更主要的目的是給大家提供一個簡單得記憶頁面生命周期的方法。

準确的記憶ASP.NET頁面生命周期每一個階段發生了什麼事情是比較困難的,一種便于記憶的方法是根據各個階段的名字組合出一個縮寫。微軟的文檔給出的ASP.NET生命周期如下:

Page Request

Start

Page Initialization

Load

Validation

Postback event handling

Rendering

Unload

根據這個組合出一個縮寫非常容易。既然Page Request技術上并不是頁面生命周期的一部分(這個階段僅僅标示我們是否開始一個頁面周期或者從緩存加載一個頁面),我們為了友善,就不包括這一階段。

S – Start

I – Initialize

L – Load

V – Validate

E – Event Handling

R – Render

這樣就組合出一個縮寫“SILVER',這個英文單詞非常好記。當然,一定要記住頁面生命周期的最後一個環節unload沒有包括在裡面。如果你覺得有必要,你可以記憶為“SILVER-U”或者“SILVER-YOU",盡管有點破壞這個記憶法的完美性。現在,我們非常容易就記住了頁面生命周期,接着我們總結一下每一步都發生了什麼,都有什麼事件伴随着發生。

在這個階段,頁面屬性,比如<code>Request</code>, <code>Response</code>, <code>IsPostBack</code>和<code>UICulture被建立。最為一個開發人員,大部分時候在這個階段你不需要做任何事。 如果你需要調用或者重寫(override)這一階段的行為,可以使用PreInit方法建立或者重新建立動态控件,設定master page或者theme或者讀取和設定profile property的值。要注意的一點是,如果是回傳(postback)的頁面請求,所有控件的值還沒有從view state裡還原,如果你在這個階段設定一個控件的值,這個值有可能在下面的階段被重寫并覆寫。</code>

這個階段對于開發人員是很重要。在這個階段,theme被應用,所有的控件都被設定了唯一的ID。開發人員在這個階段可以調用<code>Init</code>, <code>InitComplete</code>和<code>PreLoad</code> 方法。微軟關于這些方法使用的建議如下:

<code>Init</code>– 這個事件發生在所有控件被初始化并且皮膚設定也被應用後。使用這個事件來讀取控件的初始化值。

<code>InitComplete</code>–這個事件被Page對象觸發,使用這個事件處理那些要求所有初始化工作都完成後才能做的事情。

<code>PreLoad</code>- 如果在頁面或者控件進入Load事件前你有什麼要處理的,使用這個事件。Page在觸發這個事件後,Page就會為自己和所有的控件加載view state并且處理所有Request中的postback資料。

這個階段可能是開發者使用得最多的一個階段。在這個階段,所有的控件被viewstate中資訊填充并被加載,OnLoad事件被觸發。在這個階段你可以為頁面上所有的服務端控件設定屬性,得到query strings,建立資料庫連接配接。

如果你的控件要求驗證,驗證會在這個階段發生,這個時候你可以檢查控件的IsValid屬性。跟這個階段關聯的事件是Validate,它有一個可以接受驗證字元串群的重載方法(overload method),這個重載方法執行特定控件群的驗證。

所有伺服器端控件的事件處理發生在這個階段。也就是說<code>Click</code>, <code>SelectedIndexChanged</code>等等這些事件會應用到你的伺服器端控件,如果是頁面請求是回傳(postback)的話,這些事件的處理函數就會被控件觸發。這個階段可以使用的事件如下:

<code>LoadComplete</code>– 在這個階段,頁面上所有的控件加載完畢。

<code>PreRender</code>– 這裡有幾個重點,第一:頁面對象(page object)會調用每一個控件的EnsureChildControls函數,并最終調用自己的。其次:所有具有DataSourceID的資料綁定控件都會調用自己的DataBind函數。要注意的一點是,PreRender事件會發生在一個頁面的每一個控件上。在這個事件的最後,頁面和所有控件的ViewState被存儲。

<code>SaveStateComplete</code>– 到這裡,ViewState已經存儲完畢,如果你有什麼操作不需要修改控件但需要修改ViewState的,可以放在SaveStateComplete裡面。

最後這個事件首先是被各個控件逐一觸發,最後被頁面觸發。在這個時刻,所有的控件已經被渲染為輸出流(output stream)并且無法被修改。這個階段中,任何試圖對response stream的操作都會引發異常。這個事件主要用于做一些清理工作,比如關閉資料庫連接配接和打開的檔案或者登記事件記錄等等其它任務。

下面列出ASP.NET頁面生命周期中所有的方法,這些方法都可以被重寫(override),要注意的是這些方法有的會遞歸調用,有個會被頁面中的内容重複調用,這個清單是按照頁面加載時最通用的順序排列的。

<code>Construct</code>

<code>ProcessRequest</code>

<code>FrameworkInitialize</code>

<code>InitializeCulture</code>

If child controls are present:

<code>AddParsedSubObject</code>

<code>CreateControlCollection</code>

<code>AddedControl</code>

<code>ResolveAdapter</code>

<code>DeterminePostBackMode</code>

<code>OnPreInit</code>

<code>OnInit</code>

<code>TrackViewState</code>

<code>OnInitComplete</code>

<code>OnPreLoad</code>

<code>OnLoad</code>

<code>OnLoadComplete</code>

<code>EnsureChildControls</code>

<code>CreateChildControls</code>

<code>OnPreRender</code>

<code>OnPreRenderComplete</code>

<code>SaveViewState</code>

<code>OnSaveStateComplete</code>

<code>CreateHtmlTextWriter</code>

<code>RenderControl</code>

<code>Render</code>

<code>RenderChildren</code>

<code>VerifyRenderingInServerForm</code>

<code>OnUnload</code>

<code>Dispose</code>

在開發ASP.NET程式時,了解什麼時候發生什麼事情是非常重要的。了解頁面中事件是如何層層展開節省大量撓頭和查錯的時間。當這些頁面周期中的事件難以記住時,我希望這個使用的法子能幫助你梳理出在程式裡哪個地方需要做什麼處理。

我寫這篇文章是為了幫助大家,也友善了自己。即使是熟練的開發人員有時也會忘記那些先那些後。這篇文章不是面面俱到,而是希望給初學者和中級水準的開發者提供一些“小技巧”,進而幫助他們避免一些基本的錯誤。

祝使用ASP.NET一路愉快!

本文譯者:m2land

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。