前天去面試,讓我說下生命周期,本來之前就瞭解過,但是沒說出來,被深深的鄙視了;今天弄了一上午,現在發到這分享一下,有什麼錯誤請各位大牛們指出~~ 昨天面試,又遇到這問題了... 然後說了半天,人家問我一用戶控制項的周期在哪執行,我想了半天,也沒有想出來,回來只好再研究了.. 請求的本頁面Page-Lo ...
前天去面試,讓我說下生命周期,本來之前就瞭解過,但是沒說出來,被深深的鄙視了;今天弄了一上午,現在發到這分享一下,有什麼錯誤請各位大牛們指出~~
昨天面試,又遇到這問題了... 然後說了半天,人家問我一用戶控制項的周期在哪執行,我想了半天,也沒有想出來,回來只好再研究了..
請求的本頁面Page-Load->用戶自定義控制項Page-Load->本頁面渲染之前Page-PreRender 這樣一個順序
頁面發送請求原理
瀏覽器將請求封裝成Http請求報文發送到伺服器; 伺服器端HTTP.SYS內核驅動模塊來接收,這個模塊監聽著80
埠. 它首先去訪問註冊表確定請求交給誰去處理.
將請求交給了IIS IIS中分為了兩塊
1. w3svc服務 .它是寄宿在svchost.exe進程里.主要負責將請求分發給具體的擴展程式. 具體分發給誰呢?
2.配置是在InetInfo這個進程裡面. 這是iis的核心進程,這裡放著IIS的元數據.
在這裡.訪問IIS核心進程,分析當前尾碼的請求是靜態還是動態.要交給哪個擴展來處理(.aspx;.ashx 動態的交給aspnet_isapi.dll處理).如果是靜態的直接返回到HTTP.SYS 在瀏覽器中顯示,如果是動態 ,交給一個aspnet_isapi.dll這個擴展處理 在IIS5中, 是aspnet_wp.exe;在IIS6中和7中,是w3wp.exe
每一個網站都跑在一個單獨的工作進程裡面,網站間是通過進程進行隔離的.(不同的網站跑在不同的進程裡面,這個稱為應用程式池技術)
而在IIS5中,只是有一個進程,它是通過應用程式域來隔離每個進程之間的關聯;
如果是動態頁面的話.w3svc服務將請求又交給了aspnet_isapi.dll這個擴展. 這個擴展負責啟動aspnet runtime,負責創建aspnet運行環境.還負責將請求交給ISAPIRuntime的PR方法,也就是非托管和托管程式的入口
在ISAPIRuntime,這就可以看到之後的源代碼了
1.ISAPIRuntime對象 它調用了它的一個.ProcessRequest(ecb)方法; ecb是一個操作系統的句柄,指向了當前請求的記憶體空間,可以通過此句柄來拿到當前請求的報文;通過ecb句柄,創建了一個HttpWorkRequest對象.此對象就是對Http請求報文做了一些簡單的封裝.也就是請求的報文頭,報文體而已;
再一次的將請求給下麵分發
分發給了HttpRuntime這個對象, 又調用了RrocessRequest(wr)方法;將ecb句柄創建的WorkRequest對象傳進去.根據這個對象封裝了一個HttpContext(請求上下文)
HttpContext中包括了HttpRequest(封裝http請求),還有一個是 HttpResponse(封裝了Http的響應)
並且HttpRuntime還根據HttpApplicationFactory工廠 獲取一個HttpAplication對象
在這個工廠中,獲取實例的時候,先去Applition池裡去面去查看有沒有空閑的HttpApplication對象.如果有直接返回,如果沒有那麼就先編譯global文件生成一個HttpAppliction的派生類,然後根據這個派生類反射創建一個HttpAppliction類型實例並返回.
這個HttpAplication對象,調用了ProcessRequest(HttpContext context)執行19個管道事件,流動著的就是HttpContext上下文 context 這需要走23個步驟
在第8個事件中,根據請求的地址,創建一般處理程式或者是aspx頁面類型,並轉成IHttpHandler介面對象;
在第9個事件中,會接收瀏覽器發送過來的SessionId,並且根據此值到伺服器的Session池中找到對應的session對象,先嘗試將頁面類對象轉換成IRequiresSessionState介面對象,如果轉換不成功,剛不載入Session對象,如果轉換成功則 將它賦值給頁面對象的Session屬性;(Page.HttpContext.HttpSessionState)
(頁面生命周期)
第一步:創建控制項樹
在11到12個事件中.執行頁面類(一般處理程式)的ProcessRequest方法 ;先根據頁面上的每個控制項和我們寫的靜態標簽把這些基本都創建好,現在還不是正式的創建,還沒有把控制項new出來,它在初使化的時候才new;
執行_BuildControlTree()這個方法;方法內部就是將整個頁面控制項創建好,普通的C#代則被編譯到一個方法體裡面;
第二步:
決定是否是IspostBack,確定當前請求是不是回發過來的;它通過ViewState實現的;只要ViewState不為null,那麼就是回發過來的,結果就為true.
第三步:
初使化 PreInint()初使化之前的一個事件
Init() 實際初使化:就將控制項樹上的控制項都new一個實例,並賦預設值; 方法內部是執行了一個遞歸初使化;
InitComplete() 初使化完成
第四步:
載入ViewState,載入頁面的狀態;解析隱藏域中的ViewState
這個解析完成之後,下一步:
第五步:
ProcessPostDate() : 處理回發數據
1:比較表單提交過來的數據和控制項上原來的狀態做對比,然後將需要觸發改變事件的控制項放到一個集合裡面去等待觸發.(當你需要改變了一個方本框的值,它會將改變之後的和之前的做對比,將改變之後的這個控制項或標簽添加到集合中,等待改變的事件觸發);
2:將表單中的值賦值到控制項上面去.
第六步:
頁面載入
PreLoad()載入之前
Load 就是我們用的Page_Load()方法; 在這裡我們可以拿到控制項中的值
第七步:
在load之後,再一次執行ProcessPostData:第二次處理回發的數據; 為什麼要第二次呢? 允許在當面Load中再次對值進行處理;再次將需要觸發改變事件的控制項放到集合中去; 這是在事件響應之前最後的機會:引發改變事件的地方;
第八步:
LoadComplete() 載入之後
觸發改變控制項的事件,
第九步:
觸發PostBack回發控制項的事件
第十步:
PreRend() 頁面渲染之前的事件 (就是將伺服器控制項轉換成html代碼的過程)
在這個方法之前,是最後能修改我們發送給客戶端響應內容的機會;
第十一步:
保存當前頁面的狀態(將需要保存狀態的值放到ViewState中,也就是隱藏域)
第十二步:
頁面渲染 再回到到第11和第12個事件
2.托管程式:aspnet runtime
下麵是我用反編譯查看了下它內部的執行順序..
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14: