html
數據庫
編程
原文做者:Shivprasad koirala | |
原文地址:http://www.codeproject.com/Articles/73728/ASP-NET-Application-and-Page-Life-Cycle |
|
他的介紹:微軟MVP(ASP/ASP.NET),如今是印度一家小型在線教育公司的CEO。他很是積極地在製做在線培訓視頻,寫技術書籍及作企業培訓。 |
api
瀏覽器
緩存
服務器
框架
ide
post
圖2 ASP.NET環境的建立
下圖則形象地展現了在一個ASP.NET請求過程當中的重要內部對象模型。最高層是ASP.NET運行時,它建立了一個應用程序域(AppDoamin),下層則建立了一個包含request、response以及context對象的HttpRuntime。
圖3 ASP.NET請求過程當中的內部對象模型
一旦HttpApplication建立好,它就開始處理請求了。它經歷了三個不一樣的部分:HttpModule、Page和HttpHandler。當它通過這些部分時,它將調用不一樣的事件,而這些事件的邏輯處理還能夠由開發者來進行擴展和增長自定義處理。
在進一步深刻了解以前,讓咱們先來了解一下什麼是HttpModule和HttpHandlers。他們幫助咱們在ASP.NET頁面處理過程的先後注入自定義的邏輯處理。他們之間主要的差異在於:
圖4 HttpHandler
圖5 HttpModule
你能夠從這裏瞭解更多關於他們這對好基友之間的差異。
下面是請求處理過程的邏輯流程,其中有4個重要的步湊,解釋以下:
第一步(M:HttpModule):客戶端請求開始被處理。在ASP.NET引擎執行和建立HttpModule觸發事件(在此過程當中,你也能夠注入自定義邏輯)以前,有6個事件你能夠在頁面對象建立以前來使用,它們分別是:BeginRequest、AuthenticateRequest、AuthorizeRequest、ResolveRequestCache、AcquireRequestState 以及 PreRequestHandlerExecute。
第二步(H:HttpHandler):一旦以上6個事件被觸發後,ASP.NET引擎就將會調用 ProcessRequest 事件,即便你已經在項目中實現了 HttpHandler。
第三步(P:ASP.NET Page):一旦HttpHandler邏輯執行,ASP.NET頁面對象就被建立了。而ASP.NET頁面被建立,一系列的事件也會隨之被觸發,它們能夠幫助咱們自定義邏輯注入到這些事件裏邊。在此過程當中,有6個重要事件給咱們提供了佔位符,以便咱們在ASP.NET頁面中寫入邏輯,它們分別是:Init、Load、Validate、Render 和 Unload。你能夠經過記住單詞SILVER來記憶這幾個事件,S—Start(沒有任何意義,僅僅是爲了造成一個單詞),I(Init)、L(Load)、V(Validate)、E(Event)、R(Render)。
第四步(M:HttpModule):一旦頁面對象執行結束並從內存中被卸載,HttpModule提供了提交返回頁面的執行事件,一樣,在這些事件中也能夠被注入自定義的返回處理邏輯。這裏有4個重要的提交處理事件:PostRequestHandlerExecute、ReleaserequestState、UpdateRequestCache以及EndRequest。
下圖形象地展現了上面的四個步湊。
圖6 MHPM過程
一個十分有價值的問題就是在什麼事件中咱們又能夠作些什麼?下表就展現了這個問題的答案:
Section | Event | Description |
HttpModule | BeginRequest | 此事件標誌着一個新的請求,它保證在每一個請求中都會被觸發。 |
HttpModule | AuthenticateRequest | 此事件標誌ASP.NET運行時準備驗證用戶。任何身份驗證代碼均可以在此注入。 |
HttpModule | AuthorizeRequest | 此事件標誌ASP.NET運行時準備受權用戶。任何受權代碼均可以在此注入。 |
HttpModule | ResolveRequest | 在ASP.NET中咱們一般使用OutputCache指令作緩存。在這個事件中,ASP.NET運行時肯定是否可以從緩存中加載頁面,而不是從頭開始生成。任何緩存的具體活動能夠被注入這裏。 |
HttpModule | AcquireRequestState | 此事件標誌着ASP.NET運行時準備得到Session會話變量。能夠對Session變量作任何你想要作的處理。 |
HttpModule | PreRequestHandlerExecute | 剛好在ASP.NET 開始執行事件處理程序前發生。能夠預處理你想作的事。 |
HttpHandler | ProcessRequest | HttpHandler邏輯被執行。在這個部分咱們將爲每一個頁面擴展寫須要的邏輯。 |
Page | Init | 此事件發生在ASP.NET頁面且能夠用來: 一、動態地建立控件,若是你必定要在運行時建立控件; 二、任何初始化設置 三、母版頁及其設置 在這部分中咱們沒有得到viewstate、postedvalues及已經初始化的控件。 |
Page | Load | 在這部分ASP.NET控件徹底被加載且在這裏你能夠寫UI操做邏輯或任何其餘邏輯。NOTE:這個事件也是咱們最多見且最經常使用的一個事件。 |
Page | Validate | 若是在頁面上你有驗證器,你一樣想在這裏作一下檢查。 |
Page | Render | 是時候將輸出發送到瀏覽器。若是你想對最終的HTML作些修改,你能夠在這裏輸入你的HTML邏輯。 |
Page | Unload | 頁面對象從內存中卸載。 |
HttpModule | PostRequestHandlerExecute | 能夠注入任何你想要的邏輯,在處理程序執行以後。 |
HttpModule | ReleaseRequestState | 若是你想要保存對某些狀態變量的更改,例如:Session變量的值。 |
HttpModule | UpdateRequestCache | 在結束以前,你是否想要更新你的緩存。 |
HttpModule | EndRequest | 這是將輸出發送到客戶端瀏覽器以前的最後一個階段。 |
咱們能夠經過一個示例程序代碼來展現以上介紹的那些事件是怎樣被最終觸發的。在這個示例中,咱們已經建立了一個HttpModule和HttpHandler,而且也在全部的事件中經過添加自定義邏輯代碼展現了一個簡單的響應。
下面是HttpModule類,它跟蹤了全部的事件並將其添加到了一個全局的集合中。
public class clsHttpModule : IHttpModule { ...... void OnUpdateRequestCache(object sender, EventArgs a) { objArrayList.Add("httpModule:OnUpdateRequestCache"); } void OnReleaseRequestState(object sender, EventArgs a) { objArrayList.Add("httpModule:OnReleaseRequestState"); } void OnPostRequestHandlerExecute(object sender, EventArgs a) { objArrayList.Add("httpModule:OnPostRequestHandlerExecute"); } void OnPreRequestHandlerExecute(object sender, EventArgs a) { objArrayList.Add("httpModule:OnPreRequestHandlerExecute"); } void OnAcquireRequestState(object sender, EventArgs a) { objArrayList.Add("httpModule:OnAcquireRequestState"); } void OnResolveRequestCache(object sender, EventArgs a) { objArrayList.Add("httpModule:OnResolveRequestCache"); } void OnAuthorization(object sender, EventArgs a) { objArrayList.Add("httpModule:OnAuthorization"); } void OnAuthentication(object sender, EventArgs a) { objArrayList.Add("httpModule:AuthenticateRequest"); } void OnBeginrequest(object sender, EventArgs a) { objArrayList.Add("httpModule:BeginRequest"); } void OnEndRequest(object sender, EventArgs a) { objArrayList.Add("httpModule:EndRequest"); objArrayList.Add("<hr>"); foreach (string str in objArrayList) { httpApp.Context.Response.Write(str + "<br>") ; } } }
下面是HttpHandler類的一個代碼片斷,它跟蹤了ProcessRequest事件。
public class clsHttpHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { clsHttpModule.objArrayList.Add("HttpHandler:ProcessRequest"); context.Response.Redirect("Default.aspx"); } }
同上,咱們也能夠跟蹤來自ASP.NET Page頁面的全部事件。
public partial class _Default : System.Web.UI.Page { protected void Page_init(object sender, EventArgs e) { clsHttpModule.objArrayList.Add("Page:Init"); } protected void Page_Load(object sender, EventArgs e) { clsHttpModule.objArrayList.Add("Page:Load"); } public override void Validate() { clsHttpModule.objArrayList.Add("Page:Validate"); } protected void Button1_Click(object sender, EventArgs e) { clsHttpModule.objArrayList.Add("Page:Event"); } protected override void Render(HtmlTextWriter output) { clsHttpModule.objArrayList.Add("Page:Render"); base.Render(output); } protected void Page_Unload(object sender, EventArgs e) { clsHttpModule.objArrayList.Add("Page:UnLoad"); } }
下圖則顯示了上面咱們所討論的全部事件的執行順序。
圖7 示例結果—事件的執行次序
在上面的部分中,咱們已經瞭解了一個ASP.NET頁面請求事件的總體流程。那麼,在其中一個最重要的部分就是ASP.NET頁面,可是咱們並無對其進行詳細討論。所以,咱們在此深刻地瞭解一下ASP.NET頁面事件。
每個ASP.NET頁都有2個部分:一個是在瀏覽器中進行顯示的部分,它包含了HTML標籤、viewstate形式的隱藏域 以及 在HTML input中的數據。當這個頁面被提交到服務器時,這些HTML標籤會被建立到ASP.NET控件,而且viewstate還會和表單數據綁定在一塊兒。一旦你在後置代碼中獲得全部的服務器控件,你能夠執行和寫入你本身的邏輯並呈現給客戶瀏覽器。
圖8 ASP.NET頁的兩個部分
如今這些HTML控件會做爲ASP.NET控件存活在服務器上,ASP.NET會觸發一系列的事件,咱們也能夠在這些事件中注入自定義邏輯代碼。根據你想要執行什麼樣的任務/邏輯,咱們須要將邏輯合理地放入這些事件之中。
注意:大部分的開發者直接使用Page_Load來幹全部的事情,但這並非一個好的思路。所以,不管是填充控件、設置ViewState仍是應用主題等全部發生在頁面加載中的全部事情。所以,若是咱們可以在合適的事件中放入邏輯,那麼毫無疑問咱們代碼將會乾淨不少。
順序 | 事件名稱 | 控件初始化 | ViewState可用 | 表單數據可用 | 什麼邏輯能夠寫在這裏? |
1 | Init | No | No | No | 注意:你能夠經過使用ASP.NET請求對象訪問表單數據等,但不是經過服務器控件。 動態地建立控件,若是你必定要在運行時建立;任何初始化設置;母版頁及其設置。在這部分中咱們沒有得到viewstate、提交的數據值及已經初始化的控件。 |
2 | Load View State | Not guaranteed | Yes | Not guaranteed | 你能夠訪問View State及任何同步邏輯,你但願viewstate被推到後臺代碼變量能夠在這裏完成。 |
3 | PostBackdata | Not guaranteed | Yes | Yes | 你能夠訪問表單數據。任何邏輯,你但願表單數據被推到後臺代碼變量能夠在這裏完成。 |
4 | Load | Yes | Yes | Yes | 在這裏你能夠放入任何你想操做控件的邏輯,如從數據庫填充combox、對grid中的數據排序等。這個事件,咱們能夠訪問全部控件、viewstate、他們發送過來的值。 |
5 | Validate | Yes | Yes | Yes | 若是你的頁面有驗證器或者你想爲你的頁面執行驗證,那就在這裏作吧。 |
6 | Event | Yes | Yes | Yes | 若是這是經過點擊按鈕或下拉列表的改變的一個回發,相關的事件將被觸發。與事件相關的任何邏輯均可以在這裏執行。 PS:這個事件想必不少使用WebForm的開發人員都很經常使用吧,是否記得那些Button1_Click(Object sender,EventArgs e)? |
7 | Pre-render | Yes | Yes | Yes | 若是你想對UI對象作最終的修改,如改變屬性結構或屬性值,在這些控件保存到ViewState以前。 |
8 | Save ViewState | Yes | Yes | Yes | 一旦對服務器控件的全部修改完成,將會保存控件數據到View State中。 |
9 | Render | Yes | Yes | Yes | 若是你想添加一些自定義HTML到輸出,能夠在這裏完成。 |
10 | Unload | Yes | Yes | Yes | 任何你想作的清理工做均可以在這裏執行。 |
圖9 ASP.NET Page事件流程
(1)碧血軒,《ASP.NET頁面生命週期》,http://www.cnblogs.com/xhwy/archive/2012/05/20/2510178.html
(2)吳秦,《ASP.NET 應用程序與頁面生命週期(意譯)》,http://www.cnblogs.com/skynet/archive/2010/04/29/1724020.html
(3)風塵浪子,《C#綜合揭祕—細說進程、應用程序域與上下文之間的關係》,http://www.cnblogs.com/skynet/archive/2010/04/29/1724020.html
(4)菩提樹下的楊過,《溫故而知新:HttpApplication,HttpModule,HttpContext及Asp.Net頁生命週期》,http://www.cnblogs.com/yjmyzz/archive/2010/03/28/1698968.html
(5)MSDN,《ASP.NET頁面生命週期概述》,http://msdn.microsoft.com/zh-cn/library/ms178472.aspx
(6)皺華棟,《ASP.NET!=拖控件之2011版視頻教程》,http://bbs.itcast.cn/thread-8439-1-1.html