ASP.NET 頁運(yùn)行時(shí),此頁將經(jīng)歷一個(gè)生命周期,在生命周期中將執(zhí)行一系列處理步驟。這些步驟包括初始化、實(shí)例化控件、還原和維護(hù)狀態(tài)、運(yùn)行事件處理程序代碼以及進(jìn)行呈現(xiàn)。了解頁生命周期非常重要,因?yàn)檫@樣做您就能在生命周期的合適階段編寫代碼,以達(dá)到預(yù)期效果。此外,如果您要開發(fā)自定義控件,就必須熟悉頁生命周期,以便正確進(jìn)行控件初始化,使用視圖狀態(tài)數(shù)據(jù)填充控件屬性以及運(yùn)行任何控件行為代碼。(控件的生命周期基于頁的生命周期,但是頁引發(fā)的控件事件比單獨(dú)的 ASP.NET 頁中可用的事件多。)
一般來說,頁要經(jīng)歷下表概述的各個(gè)階段。除了頁生命周期階段以外,在請(qǐng)求前后還存在應(yīng)用程序階段,但是這些階段并不特定于頁。(有關(guān)更多信息,請(qǐng)參見 MSDN:ASP.NET 應(yīng)用程序生命周期概述。)
![](/upload/201201/20120103122720440.png)
我們知道最終我們?cè)诜?wù)器上創(chuàng)建的頁面對(duì)象是通過Page的一個(gè)派生類來創(chuàng)建的,這個(gè)類通常情況下是看不到的,包括類的名字也不是我們直接指定的。這個(gè)類是由ASP.NET服務(wù)器根據(jù)我們的頁面模板文件aspx創(chuàng)建出來的,頁面對(duì)象的ProcessRequest方法將會(huì)啟動(dòng)頁面的生成過程。這個(gè)過程是通過頁面的處理管道來完成的。
下表列出了最常用的頁生命周期事件。除了列出的事件外還有其他事件;不過,大多數(shù)頁處理方案不使用這些事件。而是主要由 ASP.NET 網(wǎng)頁上的服務(wù)器控件使用,以初始化和呈現(xiàn)它們本身。如果要編寫自己的 ASP.NET 服務(wù)器控件,則需要詳細(xì)了解這些階段。(有關(guān)創(chuàng)建自定義控件的信息,請(qǐng)參見MDDN:開發(fā)自定義 ASP.NET 服務(wù)器控件。 )
![](/upload/201201/20120103122720534.png)
![](/upload/201201/20120103122720670.png)
注意事項(xiàng)(來自MSDN):
各個(gè) ASP.NET 服務(wù)器控件都有自己的生命周期,該生命周期與頁生命周期類似。例如,控件的 Init 和 Load 事件在相應(yīng)的頁事件期間發(fā)生。
雖然 Init 和 Load 都在每個(gè)控件上以遞歸方式發(fā)生,但它們的發(fā)生順序相反。每個(gè)子控件的 Init 事件(還有 Unload 事件)在為其容器引發(fā)相應(yīng)的事件之前發(fā)生(由下到上)。但是,容器的 Load 事件是在其子控件的 Load 事件之前發(fā)生(由上到下)。
可以通過處理控件的事件(如 Button 控件的 Click 事件和 ListBox 控件的 SelectedIndexChanged 事件)來自定義控件的外觀或內(nèi)容。在某些情況下,可能也需處理控件的 DataBinding 或 DataBound 事件。有關(guān)更多信息,請(qǐng)參見各個(gè)控件的類參考主題以及開發(fā)自定義 ASP.NET 服務(wù)器控件。
當(dāng)從 Page 類繼承類時(shí),除了可以處理由頁引發(fā)的事件以外,還可以重寫頁的基類中的方法。例如,可以重寫頁的 InitializeCulture 方法,以便動(dòng)態(tài)設(shè)置區(qū)域性信息。注意,在使用 Page_事件語法創(chuàng)建事件處理程序時(shí),將隱式調(diào)用基實(shí)現(xiàn),因此無需在方法中調(diào)用它。例如,無論是否創(chuàng)建 Page_Load 方法,始終都會(huì)調(diào)用頁基類的 OnLoad 方法。但是,如果使用 override 關(guān)鍵字(在 Visual Basic 中為 Overrides)重寫頁的 OnLoad 方法,則必須顯式調(diào)用基方法。例如,如果在頁中重寫 OnLoad 方法,則必須調(diào)用 base.Load(在 Visual Basic 中為 MyBase.Load)以運(yùn)行基實(shí)現(xiàn)。
IIS處理Asp.net請(qǐng)求
首先我們要弄清楚兩個(gè)非常重要的概念:
1, worker process(w3wp.exe). worker process管理所有的來自客戶端的請(qǐng)求并給出響應(yīng)。它是IIS下asp.net應(yīng)用程序的核心。
2, application pool. 它是worker process的容器,IIS5及之前的IIS版本均沒有application pool的概念。每一個(gè)application pool對(duì)應(yīng)著一個(gè)worker process,在IIS Metabase中維護(hù)著Application Pool和worker process的Mapping。這就避免了IIS5中出現(xiàn)的worker process(IIS5中是aspnet_wp.exe,同一時(shí)間只能運(yùn)行一個(gè)該進(jìn)程)崩潰,application全崩潰的局面。
客戶端向IIS發(fā)出一個(gè)資源請(qǐng)求后發(fā)生了如下事情:
1, server接受該請(qǐng)求
IIS6通過內(nèi)核模式(Kernel mode)中的HTTP.SYS來分發(fā)各個(gè)Request到application pool。 這并不是隨機(jī)的過程,在application pool創(chuàng)建的時(shí)候就已經(jīng)注冊(cè)到了HTTP.SYS,所以當(dāng)請(qǐng)求來到時(shí)HTTP.SYS會(huì)直接發(fā)送到相應(yīng)的application pool。 接下來在IIS的用戶模式(User mode)中,Web Admin Services (WAS) 做了從HTTP.SYS中得到Request并分發(fā)到application pool的工作。application pool直接把request傳遞給worker process。
2, 請(qǐng)求傳遞到worker process后,worker process初始化加載ASP.NET ISAPI(Internet Server Application Program Interface),ASP.NET ISAPI進(jìn)而加載CLR創(chuàng)建托管環(huán)境。
(注:ISAPI只是一個(gè)接口,起到一個(gè)代理的作用,主要能力就是根據(jù)Request URL的后綴來尋找該后綴的處理程序)
ASP.NET ISAPI定義在aspnet_isapi.dll中,它本身運(yùn)行在一個(gè)非托管的環(huán)境中。ASP.NET ISAPI開始一個(gè)HttpRuntime, HttpRuntime調(diào)用ProcessRequest方法來開始處理請(qǐng)求。ProcessRequest根據(jù)ISAPI傳進(jìn)來的iWRType 來創(chuàng)建不同的HttpWorkerRequest,從而屏蔽了不同IIS的差異。接下來ProcessRequest方法創(chuàng)建了HttpContext,我們使用HTTPContext.Current來訪問它。在HttpRuntime使用HttpApplicationFactory創(chuàng)建了HttpApplication對(duì)象(IHttpHandler)以后,所有的請(qǐng)求都會(huì)在通過httpmodule后找到相應(yīng)的Httphandler進(jìn)行處理。在HttpApplicationFactory創(chuàng)建HttpApplication之前,會(huì)查找config(web.config和Machine.config)文件中注冊(cè)的所有的HttpModule,并根據(jù)配置信息加載相應(yīng)的Assembly,通過Reflection創(chuàng)建對(duì)應(yīng)的HttpModule,并將這些Module加到HttpApplication 的_moduleCollection Filed中。我們對(duì)一個(gè)Application的請(qǐng)求最終會(huì)落到一個(gè)HttpApplication對(duì)象上。當(dāng)一個(gè)請(qǐng)求到來時(shí),ASP.NET會(huì)在Httplication Pool中查找未被使用的HttpApplication對(duì)象。
3, 請(qǐng)求通過HTTP管道后,每個(gè)請(qǐng)求都發(fā)向相關(guān)的各自的httphandler,IIS請(qǐng)求處理過程結(jié)束。
HttpHandler是HTTP管道的終點(diǎn),它為每個(gè)request生成輸出。System.Web.UI.Page就是這樣一個(gè)典型的Httphandler,當(dāng)我們請(qǐng)求一個(gè)aspx頁面,這個(gè)HttpHandler就生成html發(fā)送回客戶端??碢age類的簽名:
public class Page : TemplateControl, IHttpHandler
{
}
可以看到,Page類就是一個(gè)HttpHandler。
綜上整個(gè)過程就是:當(dāng)客戶端向服務(wù)器發(fā)送資源請(qǐng)求時(shí),請(qǐng)求首先到達(dá)IIS的HTTP.SYS。然后HTTP.SYS發(fā)送請(qǐng)求道對(duì)應(yīng)的Application Pool。 然后Application Pool發(fā)送請(qǐng)求到Worker Process(W3WP.exe)中加載ISAPI Extension,ISAPI創(chuàng)建一個(gè)HttpRuntime對(duì)象來通過HttpModule和HttpHandler處理請(qǐng)求。 然后頁面生命周期就開始了。
4, 頁面生命周期開始
頁面生命周期的主要階段包括:
頁面初始化(Init): 服務(wù)器創(chuàng)建服務(wù)器控件的實(shí)例
加載(load): 控件實(shí)例被加載到它定義的頁面對(duì)象中
預(yù)輸出:(PreRender) 對(duì)控件的更改被更新,準(zhǔn)備輸出。
保存(SaveViewState): 控件的狀態(tài)信息被保存。
輸出頁面(Render):服務(wù)器為控件創(chuàng)建html標(biāo)記。
處理(Dispose): 主要做的工作就是dispose, 關(guān)閉數(shù)據(jù)庫連接,文件資源的釋放等。
卸載(Unload):銷毀服務(wù)器控件的實(shí)例
頁面生命周期的主要事件:
PreInit:
1.檢查IsPostBack 屬性
2.動(dòng)態(tài)設(shè)置Master Page
3.動(dòng)態(tài)設(shè)置Theme
4.設(shè)置控件的默認(rèn)值(UniqueId等)
5.重新創(chuàng)建動(dòng)態(tài)控件(初始化控件),初始化控件的值
Init: 這個(gè)事件發(fā)生在所有的控件被初始化,所有的皮膚設(shè)置被應(yīng)用以后。它用來讀取或者初始化控件屬性。它能夠用來注冊(cè)一些aspx頁面中沒有指出的控件的事件。
InitComplete: Use this event for processing tasks that require all initialization to be complete.
PreLoad: 加載頁面的ViewState和所有的控件,然后處理所有的包含在Request實(shí)例中的postback數(shù)據(jù)。
Load: 這個(gè)事件可能是大家最熟悉的了。需要注意的是,Page對(duì)象會(huì)遞歸的調(diào)用子控件的onload事件直到頁面和所有的子控件被加載完成。這個(gè)事件主要用來設(shè)置控件屬性的值,建立數(shù)據(jù)庫連接(通常不這么做)。
Control events: 這個(gè)就不多說了,主要是處理控件的事件,例如click。這也就讓我們明白了每次我們click一個(gè)Button的時(shí)候,實(shí)際上是要先去執(zhí)行l(wèi)oad事件然后才執(zhí)行click事件的,一般我們用!IsPostBack來判斷一下從而避免執(zhí)行不必要的加載邏輯。
LoadComplete: 頁面所有的控件都被加載以后執(zhí)行,暫時(shí)沒有想到用來干什么。。。
PreRender: 在HTML被生成之前這是最后一個(gè)事件。每一個(gè)頁面中的控件都有PreRender的過程。在這里對(duì)將要輸出的HTML結(jié)果進(jìn)行最后一次修改。
SaveStateComplete: 在這個(gè)時(shí)間發(fā)生之前,已經(jīng)保存了所有控件和頁面的,任何對(duì)page或者控件的改動(dòng)都不會(huì)產(chǎn)生左右。暫時(shí)沒想到用來干啥。
Render: 它不是一個(gè)事件而是一個(gè)方法。工作就是把HTML寫回客戶端瀏覽器。
UnLoad: 頁面中的每一個(gè)控件都會(huì)發(fā)生這件事。在控件中,使用這個(gè)事件來做清理工作,例如關(guān)閉數(shù)據(jù)庫連接等。對(duì)與頁面本身也是做清理工作,例如關(guān)閉打開的文件和數(shù)據(jù)庫連接,或者結(jié)束日志或者其它指定的工作。
需要說明的是,每次Request都會(huì)創(chuàng)建一個(gè)全新的Page類的實(shí)例,所以在頁面中的自己定義的字段是不能在兩次request中傳遞值的,需要使用viewstate來存儲(chǔ)。
5, HttpHandler根據(jù)頁面生命周期中事件的處理把結(jié)果發(fā)回IIS,IIS再把結(jié)果發(fā)回客戶端瀏覽器。
值得注意的是,在這個(gè)過程中請(qǐng)求會(huì)再次通過HttpModule(注冊(cè)一個(gè)EndRequest事件)。
至此,整個(gè)Request結(jié)束。
您可能感興趣的文章:- ASP.NET Web頁生命周期和執(zhí)行的方法介紹
- 詳解ASP.NET頁面生命周期事件
- 詳解ASP.NET頁面生命周期
- asp.net頁面生命周期詳解
- 驗(yàn)證一個(gè)ASP.NET應(yīng)用程序和頁面的生命周期的實(shí)現(xiàn)代碼
- ASP.NET服務(wù)器控件的生命周期分析
- IIS處理Asp.net請(qǐng)求和Asp.net頁面生命周期說明
- 深入理解Asp.Net中WebForm的生命周期