天天看點

ASP.NET處理架構

Web伺服器的消息流動階段

當裝載(hosting) ASP.NET 的 Web 伺服器接收到 HTTP 請求時,HTTP 聆聽程式 (HTTP Listener) 會将請求轉交給 URL 指定的網站應用程式的工作流程 (Worker Process),ASP.NET 的工作流程處理器(aspnet_isapi.dll,若是 IIS 5.0 時則是 aspnet_wp.exe)會解析 URL,并啟動位于 System.Web.Hosting 命名空間中的 ISAPIRuntime(視版本)對象,接收 HTTP 請求,并調用 HttpRuntime,運作 HttpRuntime.ProcessRequest(),在 ProcessRequest() 中使用 HttpApplicationFactory 建立新的 HttpApplication(或是指定的 IHttpHandler 處理器),再分派給 Page 中的 ProcessRequest() 或是 IHttpHandler 的 ProcessRequest() 方法,運作之後,再傳回到 ISAPIRuntime,以及 aspnet_isapi.dll,最後交由 HTTP Listener 回傳給用戶端,因為運作程式有如管線般順暢的運作,是以稱為 <b>HTTP Pipeline Mode</b>。

在 ASP.NET 内部的 HTTP 處理器有:

ISAPIRuntime:由 aspnet_isapi.dll 調用,初始化 HttpWorkerRequest 對象(會由IIS的版本決定要初始化的版本)。

HttpRuntime:提供請求隊列 (Request Queue)、調用 HttpWorkerRequest 中的 ProcessRequest() 方法,以及後續的處理工作。

HttpWorkerRequest:産生 HttpApplication、HttpRequest、HttpResponse 等基礎對象的 HTTP 請求對象,并将要求轉送到要處理的對象(并調用它的 ProcessRequest() 方法)。

IHttpHandler 與 IHttpAsyncHandler:負責處理 HTTP 請求的單元,由 ProcessRequest() 來分派與運作請求。

ASP.NET網頁中的事件程式

當 HttpWorkerRequest 調用 <b>ASP.NET 網頁</b>(System.Web.UI 命名空間的 Page 類)的 Page.ProcessRequest() 方法時,它會依序的引發 Page 内的各個事件,并同時調用在 Page 中所有控件的相關事件,其引發順序為:

PreInit 事件:運作預先初始化的工作,在ASP.NET 2.0中,若要動态調整主版頁面 (Master Page)、主題 (Theme) 時,要在這個事件中調整。

Init 事件:運作初始化工作。

InitCompleted 事件:在完成初始化工作後引發。

Preload 事件:運作預先加載的工作。

Load 事件:運作加載的工作,大多數的網頁都擁有 Page_Load 事件處理程式,使用者控件 (user control) 中也有 Page_Load 事件例程,都會在此時調用。

控件的 PostBack 變更通知:當網頁偵測到是 PostBack 要求時,會引發 PostBack 消息通知的事件。

控件的 PostBack 相關事件:當網頁偵測到是 PostBack 要求時,會引發 PostBack 消息指定的控件的事件。

LoadCompleted 事件:運作加載完成後的工作。

PreRender 事件:處理在産生 HTML 結果前的工作。

SaveStateCompleted 事件:處理頁面狀态(ViewState 與 ControlState)存儲完成後的事件。

Render 事件:處理産生 HTML 的工作。

Unload 事件:處理退出網頁處理時的工作。

如果 HttpWorkerRequest 調用的是實作 IHttpHandler 接口的 <b>HTTP 處理程式</b> 時,它隻會調用 IHttpHandler.ProcessRequest() 方法,由它來處理程式的輸出,不像 Page.ProcessRequest() 會處理事件順序,是以 HTTP Handler 很适合輕量級的資料處理,像是輸出檔案資料流或是圖檔資料流等。

ASP.NET的事件模型

ASP.NET 的事件模型是由 &lt;form runat="server"&gt;&lt;/form&gt; 以及數個 Hidden Field 組合而成,基于 HTTP 模型的限制,所有的網頁程式在運作結果輸出到用戶端後,程式就會退出運作,為了維護在 ASP.NET 網頁與控件的狀态資料,是以在輸出 ASP.NET 控件時,ASP.NET 會将部分狀态資料存儲到網頁的 Hidden Field 中,這類型的狀态資料稱為 <b>ViewState</b>(ID 為 __VIEWSTATE),在伺服器端即會被解譯出狀态與事件資料。在大多數的自帶 Web 控件中都有使用到這個機制,是以在使用大量 ASP.NET Web 控件的網頁中,會有許多的 ViewState 會存放在網頁中并随着 HTTP 資料流輸出到用戶端,ViewState 在輸出時,會被加密為一組亂碼字元串,其金鑰值定義在電腦中,并且每一個對象都會被串行化 (serialize) 成字元串(是以若是自定義對象要放到 ViewState 時,則應要讓它支援串行化),再輸出到 __VIEWSTATE 字段中,在每次的網頁來回時都會被傳輸,較大的 ViewState 會讓網頁大小膨脹,不利于快速的網絡傳輸,不過 ASP.NET 本身有提供将 ViewState 關閉的功能,是以如果控件不需要狀态儲存時,可将它關閉以減少輸出的大小。

為確定控件的事件能夠确實被引發,讓事件驅動能夠被運作,是以控件事件引發指令時需要的參數,是交由 JavaScript 腳本在用戶端引發時,填入另一個 Hidden Field(ID 為 __EVENTTARGET 以及 __EVENTARGUMENT),并且引發窗體的送出訓示 (submit),傳送到服務端後,服務端的 HttpApplication 中的工具函數會解析 __EVENTTARGET 和 __EVENTARGUMENT 字段中的資訊,并且交由控件所實作的 RaisePostBackEvent() 來引發事件,并由 .NET Framework 内部的事件處理機制接手處理(調用控件設定的事件處理程式)。

ASP.NET的來回模式

在 ASP.NET 運作的時候,經常會有網頁的來回動作 (round-trip),在 ASP.NET 中稱為 <b>PostBack</b>,在傳統的 ASP 技術上,判斷網頁的來回是需要由開發人員自行撰寫,到了 ASP.NET 時,開發人員可以用 Page.IsPostBack 機能來判斷是否為第一次運作(當 ASP.NET 發現 HTTP POST 要求的資料是空值時),它可以保證 ASP.NET 的控件事件隻會運作一次,但是它有個缺點(基于 HTTP POST 本身的缺陷),就是若使用者使用浏覽器的重新整理功能(按 F5 或重新整理的按鈕)重新整理網頁時,最後一次運作的事件會再被運作一次,若要避免這個狀況,必須要強迫浏覽器清空高速緩存才可以。

ASP.NET 2.0 中有新增三個來回模式:

Cross Page Postback:允許跨不同的網頁運作 PostBack,服務端可使用 Page.IsCrossPostBack 來判斷是否是跨網頁型的來回。

Async Page Mode:允許網頁使用異步的方式運作,服務端可用 Page.IsAsync 來判斷。

Callback:ASP.NET 2.0 新增的由網頁回呼用戶端指令的功能,服務端可用 Page.IsCallback 來判斷是否要求是來自 Callback。

來回模式不僅是 ASP.NET 運作時的核心,它也是 ASP.NET 應用程式的一個主要缺點,尤其是在設計複雜度高的頁面時,在網頁中隐藏的 ViewState 的大小會相當大,而在每次的來回動作中,都會傳送 ViewState 在内的窗體資訊,大量的 ViewState 會使得傳送的時間拉長,而且每次來回動作都會讓整個網頁被重新整理,而出現閃爍的情況(就算在本地端也一樣),但在AJAX技術尚未成熟時,隻能夠忍受這種因底層限制所帶來的問題,在ASP.NET AJAX技術發展出來後,通過<b>UpdatePanel</b>成功的緩解了這個問題(但 ViewState 傳送的問題仍然未根本的解決,必須要使用像 Page Method 這樣的方式才能徹底的解決)。

腳本

ASP.NET 的 Web 控件有時會包裝一些用戶端腳本 (client-side scripting),在控件被繪制時輸出到用戶端,這些腳本多數被包裝在 DLL 的資源檔中,并由 ScriptResource.axd 處理程式來輸出,開發人員也可以利用 ClientScriptManager(Page.ClientScript 屬性)中的方法來添加腳本到網頁程式中,常用的方法有:

<b>ClientScriptManager.RegisterClientScriptBlock()</b>:注冊用戶端腳本區塊 (script block)。

<b>ClientScriptManager.RegisterStartupScript()</b>:注冊在起始時運作的腳本。

<b>ClientScriptManager.RegisterOnSubmitStatement()</b>:注冊在處理窗體發送時要運作的腳本。

<b>ClientScriptManager.RegisterClientScriptInclude()</b>:注冊由外部檔案 (.js) 提供的腳本來源。

基本對象

以往在 ASP 中常被使用的五大基本對象,在 ASP.NET 中仍然持續被支援,但它們都換了一個身份來提供:

Application:包裝了 HttpApplication 對象,在程式中使用 Application 指令取得的對象,都是來自于 HttpContext.Current.Application 屬性回傳而得。

Request:包裝了 HttpRequest 對象,在程式中使用 Request 指令取得的對象,都是來自于 HttpContext.Current.Request 屬性回傳而得。

Response:包裝了 HttpResponse 對象,在程式中使用 Response 指令取得的對象,都是來自于 HttpContext.Current.Response 屬性回傳而得。

Session:包裝了 HttpSessionState 對象,在程式中使用 Session 指令取得的對象,都是來自于 HttpContext.Current.Session 屬性回傳而得。

Server:包裝了 HttpServerUtility 對象,在程式中使用 Server 指令取得的對象,都是來自于 HttpContext.Current.Server 屬性回傳而得。

延展性支援

除了 ASP.NET 網頁以外,.NET Framework 還提供了兩種可以由開發人員自行發展處理模型的子產品,一種是<b>HTTP Handler</b>,另一種則是<b>HTTP Module</b>。

HTTP Handler(擴充名為 .ashx)由 System.Web.IHttpHandler 接口定義了必要的方法(可支援異步的 HTTP Handler 稱為 HTTP Async Handler,由 System.Web.IHttpAsyncHandler 接口定義),其中最重要的方法是 ProcessRequest() 方法,開發人員必須要實作這個方法,才能夠讓 HTTP Handler 有作用,它也可以通過 ASP.NET 的組态設定,讓 HTTP Handler 可以處理特定的擴充名,它可以被視為 .NET Framework 中的 ISAPI Extensions 實作方法。

HTTP Module 則是由 System.Web.IHttpModule 接口定義,它可以在整個網頁生命周期中被調用多次,并實際處理由 HttpApplication 所引發的事件,開發人員需要實作 IHttpModule.Init() 方法,以及處理 HttpApplication 事件需要的代碼。它可被視為 .NET Framework 中的 ISAPI Filter 實作方法。

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

繼續閱讀