【譯】ASP.NET應用程序和頁面生命週期

爲什麼翻譯此文

  1、此文是Code Project社區2010年4月ASP.NET板塊的最佳文章,說明了此文的分量;html

  2、鍛鍊本身的英文技術文章翻譯能力,提升英文技術文檔閱讀能力;數據庫

  3、瞭解掌握ASP.NET頁面生命週期是很是必要的,這有助於咱們更加靈活的控制頁面,以咱們須要的方式編程開發;編程

關於原文做者

原文做者:Shivprasad koirala
原文地址:http://www.codeproject.com/Articles/73728/ASP-NET-Application-and-Page-Life-Cycle
他的介紹:微軟MVP(ASP/ASP.NET),如今是印度一家小型在線教育公司的CEO。他很是積極地在製做在線培訓視頻,寫技術書籍及作企業培訓。

內容導讀

  • 概述
  • 大致上的兩步處理流程
  • ASP.NET環境的建立
  • 經過MHPM觸發的事件處理請求
  • 在什麼事件中咱們能夠作什麼?
  • 一個簡單的示例
  • 詳解ASP.NET頁面事件

1、概述

  在本文中,咱們會試着瞭解用戶在瀏覽器中發出一個Web請求 到 這個請求被響應並顯示在瀏覽器中的過程當中究竟會發生哪些不一樣的事件。首先,咱們先試着瞭解一下ASP.NET請求的兩個大致上的步湊,而後咱們將關注點轉移到從'HttpHandler'、'HttpModule'以及ASP.NET頁面對象所觸發的不一樣事件上。當咱們進入這個事件之旅時,咱們也會試着明白在請求處理的每一個事件當中咱們能夠作什麼業務邏輯處理操做。api

2、大致上的兩步處理流程

  大致上,ASP.NET請求的處理流程分爲以下圖所示的兩個步湊。用戶發送一個請求到IIS服務器時:瀏覽器

  (1)ASP.NET會建立一個可以處理請求的環境。換句話說,它會建立一個包含請求、響應以及上下文對象的應用程序對象來處理這個請求。緩存

  (2)一旦ASP.NET環境被建立,用戶請求就會經過由modules(管道)、handlers(處理程序)和page objects(頁面對象)觸發的一系列事件進行處理。簡而言之,咱們暫且將此步湊稱爲MHPM(Module、Handler、Page和Module Event)。服務器

Two Main Steps

 

  圖1 ASP.NET的兩個主要處理步湊框架

  在接下來的部分中,咱們會深刻地理解這兩個主要的步湊。ide

3、ASP.NET環境的建立

  第一步:用戶請求到達IIS後,IIS首先會檢查哪個ISAPI擴展可以處理這個請求,這會取決於文件的後綴名。例如:若是請求的是一個'.aspx'的頁面,那麼就會被傳遞到'aspnet_isapi.dll'來進行處理。post

  第二步:若是這是該網站的首次請求,那麼一個稱爲'ApplicationManager'的類會首先建立一個該網站能夠運行的應用程序域(App Domain)。正如咱們所知,應用程序域隔離部署在同一臺IIS服務器上的兩個不一樣的Web應用程序。所以,即便其中一個應用程序域出現了錯誤,也不會影響其餘應用程序域的正常運做。

Note:下面的內容是我補充的,非原文內容。

.NET平臺下,程序集並無直接加載進 進程 中(傳統的Win32程序是直接承載的)。.NET可執行程序承載在進程的一個邏輯分區中,術語稱應用程序域(簡稱AppDomain)。應用程序域是.NET引入的一個新概念,它比進程所佔用的資源要少,能夠被看做是一個 輕量級的進程

在一個進程中能夠包含多個應用程序域,一個應用程序域能夠裝載一個可執行程序(*.exe)或者多個程序集(*.dll)。這樣可使應用程序域之間實現深度隔離,因此:即便進程中的某個應用程序域出現錯誤,也不會影響其餘應用程序域的正常運做。

更多關於AppDomain的介紹,請自行搜索,這裏再也不贅述。

  第三步:在新建立的應用程序域中,會建立ASP.NET的宿主環境,也就是HttpRuntime對象。一旦宿主環境被建立完成,ASP.NET最核心的對象如HttpContextHttpRequestHttpResponse對象都會被建立好。

  第四步:一旦全部核心的ASP.NET對象被建立好,HttpApplication對象就會隨之被建立來服務這個請求。若是你的系統中存在一個global.asax文件,那麼這個global.asax文件的對象也會被建立。可是,須要注意的是你的global.asax須要繼承自HttpApplication類。

  注意:在一個ASP.NET頁面第一次附加到網站,一個HttpApplication實例便隨之產生。爲了最大化得提升處理性能,HttpApplication的實例將會被複用以處理多個請求。

Note:下面的內容是我補充的,非原文內容。

Global.asax 文件(也稱做 ASP.NET 應用程序文件)是可選文件,包含用於響應 ASP.NET 或 HttpModule 引起的應用程序級別事件的代碼。(換句話說,咱們能夠自定義後面咱們所要介紹的一些事件,由於請求處理流程會經歷後面的10多個事件,咱們能夠寫代碼來自定義其中的一些事件,加一些咱們想作的業務邏輯操做,好比:URL重寫、身份驗證、圖片水印等等。)

若是不定義該文件,ASP.NET 頁框架假設您未定義任何應用程序或會話事件處理程序。

  第五步:此時HttpApplication對象將會被分配給一系列的ASP.NET核心對象來處理請求的頁面。

  第六步:這時,HttpApplication開始經過HTTP管道事件、處理程序(Handlers)和頁面事件來處理請求了。也就是說:它會觸發 MHPM 中的事件來處理請求。

  麼麼嗒,你也能夠經過下圖來詳細地瞭解這幾個步湊。

Create Environment Steps

  圖2 ASP.NET環境的建立

  下圖則形象地展現了在一個ASP.NET請求過程當中的重要內部對象模型。最高層是ASP.NET運行時,它建立了一個應用程序域(AppDoamin),下層則建立了一個包含request、response以及context對象的HttpRuntime。

General Explain Steps

 圖3 ASP.NET請求過程當中的內部對象模型

4、經過MHPM觸發的事件處理請求

  一旦HttpApplication建立好,它就開始處理請求了。它經歷了三個不一樣的部分:HttpModulePageHttpHandler。當它通過這些部分時,它將調用不一樣的事件,而這些事件的邏輯處理還能夠由開發者來進行擴展和增長自定義處理。

  在進一步深刻了解以前,讓咱們先來了解一下什麼是HttpModuleHttpHandlers。他們幫助咱們在ASP.NET頁面處理過程的先後注入自定義的邏輯處理。他們之間主要的差異在於:

  • 若是你想要注入的邏輯是基於像'.aspx','.html'這樣的擴展名,那麼你可使用HttpHandler。換句話說,HttpHandler是一個基於處理器的擴展。

HttpHandler Show

圖4 HttpHandler

  • 若是你想要在ASP.NET管道事件中注入邏輯,那麼你可使用HttpModule。也能夠說,HttpModule是一個基於處理器的事件。

HttpModule Show

圖5 HttpModule

  你能夠從這裏瞭解更多關於他們這對好基友之間的差異。

  下面是請求處理過程的邏輯流程,其中有4個重要的步湊,解釋以下:

  第一步(M:HttpModule):客戶端請求開始被處理。在ASP.NET引擎執行和建立HttpModule觸發事件(在此過程當中,你也能夠注入自定義邏輯)以前,有6個事件你能夠在頁面對象建立以前來使用,它們分別是:BeginRequestAuthenticateRequestAuthorizeRequestResolveRequestCacheAcquireRequestState 以及 PreRequestHandlerExecute

  第二步(H:HttpHandler):一旦以上6個事件被觸發後,ASP.NET引擎就將會調用 ProcessRequest 事件,即便你已經在項目中實現了 HttpHandler

  第三步(P:ASP.NET Page):一旦HttpHandler邏輯執行,ASP.NET頁面對象就被建立了。而ASP.NET頁面被建立,一系列的事件也會隨之被觸發,它們能夠幫助咱們自定義邏輯注入到這些事件裏邊。在此過程當中,有6個重要事件給咱們提供了佔位符,以便咱們在ASP.NET頁面中寫入邏輯,它們分別是:InitLoadValidateRender Unload。你能夠經過記住單詞SILVER來記憶這幾個事件,S—Start(沒有任何意義,僅僅是爲了造成一個單詞),I(Init)、L(Load)、V(Validate)、E(Event)、R(Render)。

  第四步(M:HttpModule):一旦頁面對象執行結束並從內存中被卸載,HttpModule提供了提交返回頁面的執行事件,一樣,在這些事件中也能夠被注入自定義的返回處理邏輯。這裏有4個重要的提交處理事件:PostRequestHandlerExecuteReleaserequestStateUpdateRequestCache以及EndRequest

  下圖形象地展現了上面的四個步湊。

MHPM

圖6 MHPM過程

5、在什麼事件中咱們能夠作什麼?

  一個十分有價值的問題就是在什麼事件中咱們又能夠作些什麼?下表就展現了這個問題的答案:

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 這是將輸出發送到客戶端瀏覽器以前的最後一個階段。

6、一個簡單的示例

  咱們能夠經過一個示例程序代碼來展現以上介紹的那些事件是怎樣被最終觸發的。在這個示例中,咱們已經建立了一個HttpModuleHttpHandler,而且也在全部的事件中經過添加自定義邏輯代碼展現了一個簡單的響應。

  下面是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>") ;
}
} 
}
View Code

  下面是HttpHandler類的一個代碼片斷,它跟蹤了ProcessRequest事件。

public class clsHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
clsHttpModule.objArrayList.Add("HttpHandler:ProcessRequest");
context.Response.Redirect("Default.aspx");
}
}
View Code

  同上,咱們也能夠跟蹤來自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");
}
}
View Code

  下圖則顯示了上面咱們所討論的全部事件的執行順序。

A Sample Demo

圖7 示例結果—事件的執行次序

7、詳解ASP.NET頁面事件

  在上面的部分中,咱們已經瞭解了一個ASP.NET頁面請求事件的總體流程。那麼,在其中一個最重要的部分就是ASP.NET頁面,可是咱們並無對其進行詳細討論。所以,咱們在此深刻地瞭解一下ASP.NET頁面事件。

  每個ASP.NET頁都有2個部分:一個是在瀏覽器中進行顯示的部分,它包含了HTML標籤、viewstate形式的隱藏域 以及 在HTML input中的數據。當這個頁面被提交到服務器時,這些HTML標籤會被建立到ASP.NET控件,而且viewstate還會和表單數據綁定在一塊兒。一旦你在後置代碼中獲得全部的服務器控件,你能夠執行和寫入你本身的邏輯並呈現給客戶瀏覽器。

ASP.NET Page

圖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 任何你想作的清理工做均可以在這裏執行。

Page Events in Detail

圖9 ASP.NET Page事件流程

一張圖複習ASP.NET請求處理(本身補充,非原文內容)

翻譯中參考的資料 

(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

 

相關文章
相關標籤/搜索