天天看點

.NET (C#) Internals: ASP.NET 應用程式與頁面生命周期(意譯)

1、引言

2、兩個處理步驟

2.1、建立ASP.NET環境

2.2、用觸發的MHPM事件處理請求

3、什麼事件中應該做什麼

4、示例代碼

5、深入ASP.NET頁面事件

這篇文章我們将試圖了解,從使用者發送一個請求直到請求呈現到浏覽器發生的事件的差異。是以,我們首先将介紹解ASP.NET請求的兩個概括的步驟,接下來我們将介紹‘HttpHandler’,‘HttpModule’和ASP.NET頁面對象發出的事件的差異。随着我們的事件旅程,我們将了解這些事件的邏輯。

ASP.NET請求處理可以總結為如下所示的兩個處理步驟。使用者發送一個請求到IIS:

ASP.NET建立處理請求的環境。換句話說,建立應用程式對象、request、response和context對象去處理請求。

一旦環境已經建立,請求通過使用modules、handlers和page對象的一系列事件處理。為了簡化可以稱為MHPM(module、handler、page、module event),我們将在後面詳細讨論。

<a target="_blank" href="http://blog.51cto.com/attachment/201008/160426117.jpg"></a>

圖1、ASP.NET請求處理的兩個步驟

在接下來的各節,我們将知道更多關于這兩個步驟的細節。

step 1:使用者發送一個請求到IIS。IIS首先檢查哪個ISAPI擴充可以處理這個請求,這取決于請求的檔案擴充名。舉例來說,如果請求頁面是‘.ASPX’,它将被傳送到‘aspnet_isapi.dll’來處理。

step 2:如果這是www站點的第一個請求,ApplicationManager類将建立一個應用程式域,www站點運作于其中。我們都知道在同一個IIS上,兩個web應用程式的應用程式域是獨立的(隔離的)。是以一個應用程式域中問題不會的影響到其它應用程式域。

step 3:建立的應用程式域建立宿主環境,如HttpRuntime對象。一旦宿主環境被建立,必要的ASP.NET核心對象如HttpContext、HttpRequest和HttpRespone對象也被建立。

step 4:一旦所有的ASP.NET核心對象被建立,HttpApplication對象将被建立去處理請求。如果系統中有global.asax檔案,global.asax檔案對象将被建立。請注意:global.asax檔案繼承自HttpApplication類。

注意:第一次ASP.NET頁面連接配接到應用程式,一個HttpApplication新執行個體将被建立。為了最大化性能,HttpApplication執行個體可能被多個請求重用。

step 5:接下來HttpApplication對象配置設定給核心ASP.NET對象來處理頁面。

<a target="_blank" href="http://blog.51cto.com/attachment/201008/160539284.jpg"></a>

圖2、建立ASP.NET環境

下圖解釋了ASP.NET請求的内部對象模型。最高層是ASP.NET運作時,它已經建立一個應用程式域(AppDomain),相應地有HttpRuntime包括request、respone、context對象。

<a target="_blank" href="http://blog.51cto.com/attachment/201008/160639888.jpg"></a>

圖3、ASP.NET請求的内部對象模型

一旦建立了HttpApplication,它開始處理請求,它經曆3個不同的部分HttpModule、Page、HttpHandler。随着它移動到這些部分,将調用不同的事件,開發人員可以擴充和定制同一邏輯。在我們前進之前讓我們了解什麼是HttpModule和HttpHandlers。他們幫組我們在ASP.NET頁處理的前後注入自定義邏輯。他們之間的主要差别是:

如果你想要注入的邏輯是基于像‘.ASPX’、‘.HTML’這樣的檔案擴充名,使用HttpHandler。換句話說HttpHandler是基于處理器的擴充。

<a target="_blank" href="http://blog.51cto.com/attachment/201008/160756340.jpg"></a>

如果你想在ASP.NET管道事件中注入邏輯,使用HttpModule。換言之是基于處理器的事件。

<a target="_blank" href="http://blog.51cto.com/attachment/201008/160844270.jpg"></a>

Step 1(M   HttpModule):用戶端請求處理開始。ASP.NET引擎開始和建立HttpModule發出事件(你可以注入定制邏輯)之前,有6個重要事件你可以使用:BeginRequest、AuthenticateRequest、AuthorizeRequest、ResolveRequestCache、AcquireRequestState和PreRequestHandlerExecute。

Step 2(H   HttpHandler):一旦上面6個事件觸發,ASP.NET引擎将調用ProcessRequest事件,即使你已經在項目中執行了HttpHandler。

Step 3(P   ASP.NET page):一旦HttpHandler邏輯執行,ASP.NET page對象被建立。ASP.NET page對象被建立,許多事件被觸發,你可以在這些頁面事件中寫我們自定義的邏輯。有6個重要事件給我們提供占位,在ASP.NET頁中寫邏輯:Init、Load、Validate、Event、Render、Unload。你可以記住單詞SILVER來記這些事件,S-Start(沒有任何意義,僅僅是為了形成一個單詞),I(Init)、L(Load)、V(Validate)、E(Event)、R(Render)。

Step 4(M   HttpModule):一旦頁面對象執行了且從記憶體中解除安裝,HttpModule提供發送頁面執行事件,它們可用于注入自定義post-處理邏輯。有4個重要的post-處理事件,PostRequestHandlerExecute、PostRequestState、UpdateRequestCache、EndRequest。

下圖展示了上面的過程。

<a target="_blank" href="http://blog.51cto.com/attachment/201008/160938225.jpg"></a>

下面的表格展示了什麼事件中做什麼邏輯或代碼。

Section

Event

Description

HttpModule

BeginRequest

此事件标志着一個新的請求,他保證在每個請求中都有。

AuthenticateRequest

此事件标志ASP.NET運作時準備驗證使用者。任何身份驗證代碼都可以在此注入。

AuthorizeRequest

此事件标志ASP.NET運作時準備授權使用者。任何授權代碼都可以在此注入。

ResolveRequest

在ASP.NET中我們通常使用OutputCache指令做緩存。在這個事件中,ASP.NET運作時确定是否能夠從緩存中加載頁面,而不是從頭開始生成。任何緩存的具體活動可以被注入這裡。

AcquireRequestState

此事件标志着ASP.NET運作時準備獲得會話變量。可以對會話變量做任何你想要的處理。

PreRequestHandlerExecute

恰好在ASP.NET 開始執行事件處理程式前發生。可以預處理你想做的事。

HttpHandler

ProcessRequest

HttpHandler邏輯被執行。在這個部分我們将為每個頁面擴充名寫需要的邏輯。

Page

Init

此事件發生在ASP.NET頁面且可以用來: 

1、動态地建立控件,如果你一定要在運作時建立控件; 

2、任何初始化設定 

3、母版頁及其設定 

在這部分中我們沒有獲得viewstate、postedvalues及已經初始化的控件。

Load

在這部分ASP.NET控件完全被加載且在這裡你可以寫UI操作邏輯或任何其他邏輯。

Validate

如果在頁面上你有驗證器,你同樣想在這裡檢查。

Render

是時候将輸入發送到浏覽器。如果你想對最終的HTML做些修改,你可以在這裡輸入你的HTML邏輯。

Unload

頁面對象從記憶體中解除安裝。

PostRequestHandlerExecute

可以注入任何你想要的邏輯,在處理程式執行之後。

ReleaseRequestState

想儲存更新某些狀态變量,如會話變量。

UpdateRequestCache

在結束之前是否更新你的緩存。

EndRequest

這是将輸出發送到用戶端浏覽器之前的最後一個階段。

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("&lt;hr&gt;");  

foreach (string str in objArrayList)  

httpApp.Context.Response.Write(str + "&lt;br&gt;") ;  

}   

下面是HttpHandler的代碼片段,它跟蹤ProcessRequest事件。

public class clsHttpHandler : IHttpHandler  

public void ProcessRequest(HttpContext context)  

clsHttpModule.objArrayList.Add("HttpHandler:ProcessRequest");  

context.Response.Redirect("Default.aspx");  

我們也追蹤ASP.NET頁面的所有事件。

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");  

}} 

下面顯示上面讨論的所有事件的執行順序:

<a target="_blank" href="http://blog.51cto.com/attachment/201008/161221297.jpg"></a>

在前面部分我們已經知道ASP.NET頁面請求的整體事件流,但是我們沒有詳細讨論,是以本節我們将深入了解。任何ASP.NET頁面有2個部分,一個是顯示在浏覽器上的頁面,它有HTML标記、viewstate形式的隐藏值、HTML inputs上的資料。當頁面被發送時,在伺服器上這些HTML标記被建立到ASP.NET控件且viewstate和表單資料捆綁在一起。一旦你得到這些伺服器控件的背景代碼,你可以執行和寫你自己的邏輯和呈現傳回給浏覽器。

<a target="_blank" href="http://blog.51cto.com/attachment/201008/161259906.jpg"></a>

現在這些HTML控件在伺服器上作為ASP.NET控件,ASP.NET頁面發出一些事件,我們可以注入自己的邏輯。根據任務/你要執行的邏輯,我們需要把這些邏輯放入适當的事件中。

注意:大部分開發者直接使用Page_Load方法執行一切,這不是一個好的方法。是以,不是填充控件、設定viewstate、應用主題等一切都發生在頁面加載上。是以,如果我們能在适當的事件中放入邏輯,将真正使你的代碼幹淨。

Seq

Events

控件初始化

Viewstate可用

表單資料可用

什麼邏輯可以寫在這裡?

1

No

注意:你可以通過使用ASP.NET請求對象通路表單資料等,但是不是通過伺服器控件。

動态地建立控件,如果你一定要在運作時建立;任何初始化設定;母版頁及其設定。在這部分中我們沒有獲得viewstate、postedvalues及已經初始化的控件。

2

Load View State

Not guaranteed

Yes

你可以通路View State及任何同步邏輯,你希望viewstate被推倒背景代碼變量可以在這裡完成。

3

PostBackdata

捏可以通路表單資料。任何邏輯,你希望表單資料被推倒背景代碼變量可以在這裡完成。

4

在這裡你可以放入任何你想操作控件的邏輯,如從資料庫填充combox、對grid中的資料排序等。這個事件,我們可以通路所有控件、viewstate、發送的值。

5

如果你的頁面有驗證器或者你想為你的頁面執行驗證,那就在這裡做吧。

6

如果這是通過點選按鈕或下拉清單的改變的一個回發,相關的事件将被觸發。與事件相關的任何邏輯都可以在這裡執行。

7

Pre-render

如果你想對UI對象做最終的修改,如改變屬性結構或屬性值,在這些控件儲存到ViewState之前。

8

Save ViewState

一旦對伺服器控件的所有修改完成,可以儲存控件資料到View State。

9

如果你想添加一些自定義HTML到輸出,可以在這裡完成。

10

做任何你想做的清理工作。

<a target="_blank" href="http://blog.51cto.com/attachment/201008/161356702.jpg"></a>

另附幾篇相關的文章:

<a target="_blank" href="http://skynet.blog.51cto.com/1943397/366345">DotText源碼學習——ASP.NET的工作機制</a>

     本文轉自Saylor87 51CTO部落格,原文連結:http://blog.51cto.com/skynet/365670,如需轉載請自行聯系原作者

繼續閱讀