關於 event 執行的順序,在 MSDN 上通常叫做「XXX Lifecycle」,例如 Application Lifecycle、Page Lifecycle 等,雖然各別來看 Application Level &Page Level 的 event sequence 都很清楚,但是 Application events 和 Page events 之間的先後順序呢?
更嚴重的問題是,若採用貼近 Microsoft 所建議的開發模式,Page 上免不了會套用 MasterPage、UserControl、和 Custom Control,這些 Control(這個詞好像不太好=.=)都有自己的 code-behind,因此也都有自己的 Init、Load、Unload 等等 event,
那麼這些 events 跟 Application 和 Page events 之間的先後順序又是怎麼樣呢?
而且不要忘記了,MasterPage 上可以擺 UserContrl,而 UserControl 上還可以使用 CustomControl 呢!
(喜歡自己用 JSON 手工打造 UI 的網站可能不會用到這麼多東西)
幸好透過偉大的 Google,我們可以找到ranking 很高的示意圖,但是!製圖時間已經是 2004 年,也沒有把 Application Event 納入。
另外一個更新的 reference 是 Jeff 這個好人的 blog post,但看了下面的留言就會發現,這是根據某個 pre-beta 版本而做出來的結果,不符合 production 版的 ASP.NET 2.0 的行為。(經過實測也發現,有些 Jeff 列出的 event 現在已經被拿掉了)
(Update 3/1: 這應該就是親愛的小馬王同學的 reference 來源吧?)
那麼到底要如何能夠隨時隨地確認 ASP.NET 的 complete event sequence 呢?!
當然是老老實實的一個一個去實作每個 event 的 event handler,然後以 trace/log 的方式來紀錄事件觸發的順序呀!
為了驗證 ASP.NET 2.0+ 的完整 event sequence,我做了一個簡單的 application,一一實作每個 event 的 event handler,在其中用 log4net 將 event 資訊寫到 .csv 檔中。
為了區別事件是在哪裡發生的,我用了「MasterPage」、「ContentPage」、「UserControlPage」和「CustomControl」等 prefix,並且輸出 UserControl 和 CustomControl 的 ClientID,以利識別 control 所在的頁面。
稍微觀察一下就會發現一些有趣的地方,例如 DataBinding 相關 event 被觸發的次數、相同事件 (e.g., Init) 在不同 Page 會有不同的順序,Session 載入的時機 … 等等。
基本上目前實作的 event handler 都是參考 MSDN 的說明,Jeff 所列出的 event 有些很有趣,例如與 ViewState 相關的 event,但是我挑了幾個來實作都無效,砍尼有空可以再幫我加強這個部份 :p
經過一些整理,完整的 event sequence 長得像下面這個樣子:
(好的 visualization 真的很重要呀 … 這裡論上應該可以弄成一顆樹,會比較好看)
Application_Start |
Application_BeginRequest |
Application_AuthenticateRequest |
Application_PostAuthenticateRequest |
Application_AuthorizeRequest |
Application_PostAuthorizeRequest |
Application_ResolveRequestCache |
Application_PostResolveRequestCache |
ContentPage_Constructor |
Application_PostMapRequestHandler |
Session_Start |
Application_AcquireRequestState |
Application_PostAcquireRequestState |
Application_PreRequestHandlerExecute |
ContentPage_PreInit |
MasterPage_Constructor |
UserControlPage_Constructor_ |
UserControlPage_Constructor_ |
UserControlPage_Constructor_ |
UserControlPage_Constructor_ |
UserControlPage_Constructor_ |
UserControlPage_Constructor_ |
CustomControl_OnInit_ctl00_ContentPlaceHolder1_MyUserControl1_MyCustomControl1 |
ContentPage_GridView1_Init_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
UserControlPage_Init_ctl00_ContentPlaceHolder1_MyUserControl1 |
CustomControl_OnInit_ctl00_ContentPlaceHolder1_MyCustomControl1 |
ContentPage_GridView1_Init_ctl00_ContentPlaceHolder1_GridView1 |
CustomControl_OnInit_ctl00_MyUserControl1_MyCustomControl1 |
ContentPage_GridView1_Init_ctl00_MyUserControl1_GridView1 |
UserControlPage_Init_ctl00_MyUserControl1 |
CustomControl_OnInit_ctl00_MyCustomControl1 |
ContentPage_GridView1_Init_ctl00_GridView1 |
MasterPage_Init |
ContentPage_Init |
ContentPage_InitComplete |
ContentPage_PreLoad |
ContentPage_Load |
MasterPage_Load |
UserControlPage_Load_ctl00_ContentPlaceHolder1_MyUserControl1 |
CustomControl_OnLoad_ctl00_ContentPlaceHolder1_MyUserControl1_MyCustomControl1 |
ContentPage_GridView1_Load_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
CustomControl_OnLoad_ctl00_ContentPlaceHolder1_MyCustomControl1 |
ContentPage_GridView1_Load_ctl00_ContentPlaceHolder1_GridView1 |
UserControlPage_Load_ctl00_MyUserControl1 |
CustomControl_OnLoad_ctl00_MyUserControl1_MyCustomControl1 |
ContentPage_GridView1_Load_ctl00_MyUserControl1_GridView1 |
CustomControl_OnLoad_ctl00_MyCustomControl1 |
ContentPage_GridView1_Load_ctl00_GridView1 |
ContentPage_LoadComplete |
ContentPage_PreRender |
MasterPage_PreRender |
UserControlPage_PreRender_ctl00_ContentPlaceHolder1_MyUserControl1 |
ContentPage_GridView1_DataBinding_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_DataBound_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_PreRender_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
ContentPage_GridView1_DataBinding_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_DataBound_ctl00_ContentPlaceHolder1_GridView1 |
ContentPage_GridView1_PreRender_ctl00_ContentPlaceHolder1_GridView1 |
UserControlPage_PreRender_ctl00_MyUserControl1 |
ContentPage_GridView1_DataBinding_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_DataBound_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_PreRender_ctl00_MyUserControl1_GridView1 |
ContentPage_GridView1_DataBinding_ctl00_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_GridView1 |
ContentPage_GridView1_RowCreated_ctl00_GridView1 |
ContentPage_GridView1_RowDataBound_ctl00_GridView1 |
ContentPage_GridView1_DataBound_ctl00_GridView1 |
ContentPage_GridView1_PreRender_ctl00_GridView1 |
ContentPage_SaveStateComplete |
CustomControl_Render_ctl00_ContentPlaceHolder1_MyUserControl1_MyCustomControl1 |
CustomControl_Render_ctl00_ContentPlaceHolder1_MyCustomControl1 |
CustomControl_Render_ctl00_MyUserControl1_MyCustomControl1 |
CustomControl_Render_ctl00_MyCustomControl1 |
CustomControl_Unload_ctl00_ContentPlaceHolder1_MyUserControl1_MyCustomControl1 |
CustomControl_Dispose_ctl00_ContentPlaceHolder1_MyUserControl1_MyCustomControl1 |
ContentPage_GridView1_Unload_ctl00_ContentPlaceHolder1_MyUserControl1_GridView1 |
UserControlPage_Unload_ctl00_ContentPlaceHolder1_MyUserControl1 |
CustomControl_Unload_ctl00_ContentPlaceHolder1_MyCustomControl1 |
CustomControl_Dispose_ctl00_ContentPlaceHolder1_MyCustomControl1 |
ContentPage_GridView1_Unload_ctl00_ContentPlaceHolder1_GridView1 |
CustomControl_Unload_ctl00_MyUserControl1_MyCustomControl1 |
CustomControl_Dispose_ctl00_MyUserControl1_MyCustomControl1 |
ContentPage_GridView1_Unload_ctl00_MyUserControl1_GridView1 |
UserControlPage_Unload_ctl00_MyUserControl1 |
CustomControl_Unload_ctl00_MyCustomControl1 |
CustomControl_Dispose_ctl00_MyCustomControl1 |
ContentPage_GridView1_Unload_ctl00_GridView1 |
MasterPage_Unload |
ContentPage_Unload |
Application_PostRequestHandlerExecute |
Application_ReleaseRequestState |
Application_PostReleaseRequestState |
Application_UpdateRequestCache |
Application_PostUpdateRequestCache |
Application_EndRequest |
Application_PreSendRequestHeaders |
Application_PreSendRequestContent |
Session_End |
Application_Disposed |
Application_End |
PS. log4net 幫我寫的第一筆紀錄的時間格式很詭異,開頭多了一個「þÿ」,如果有高手知道這是甚麼鬼東西,麻煩指點一下 :D
1 則留言:
原來你和 PY 的關係那麼親密啊 XDDD
生命週期這東西我都是遇到時才寫程式去測
感謝 Tim 做了測試,以後可以少費點工啦 哈
張貼留言