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 回傳給客戶端,因為運行程序有如管線般順暢的運行,因此稱為?HTTP Pipeline Mode。
在 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 調用?ASP.NET 網頁(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 接口的?HTTP 處理程序?時,它只會調用 IHttpHandler.ProcessRequest() 方法,由它來處理程序的輸出,不像 Page.ProcessRequest() 會處理事件順序,因此 HTTP Handler 很適合輕量級的數據處理,像是輸出文件數據流或是圖片數據流等。
?
ASP.NET的事件模型
ASP.NET 的原始設計構想,就是要讓開發人員能夠像 VB 開發工具那樣,可以使用事件驅動式程序開發模式 (Event-Driven Programming Model) 的方法來開發網頁與應用程序,若要以ASP技術來做到這件事的話,用必須要使用大量的輔助信息,像是查詢字符串或是窗體字段數據來識別與判斷對象的來源、事件流向以及調用的函數等等,需要撰寫的代碼量相當的多,但 ASP.NET 很巧妙利用窗體字段和JavaScript腳本把事件的傳遞模型隱藏起來了。
ASP.NET 的事件模型是由 <form runat="server"></form> 以及數個 Hidden Field 組合而成,基于 HTTP 模型的限制,所有的網頁程序在運行結果輸出到客戶端后,程序就會退出運行,為了維護在 ASP.NET 網頁與控件的狀態數據,因此在輸出 ASP.NET 控件時,ASP.NET 會將部分狀態數據存儲到網頁的 Hidden Field 中,這類型的狀態數據稱為?ViewState(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 中稱為?PostBack,在傳統的 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技術發展出來后,通過UpdatePanel成功的緩解了這個問題(但 ViewState 傳送的問題仍然未根本的解決,必須要使用像 Page Method 這樣的方式才能徹底的解決)。
腳本
ASP.NET 的 Web 控件有時會包裝一些客戶端腳本 (client-side scripting),在控件被繪制時輸出到客戶端,這些腳本多數被包裝在 DLL 的資源檔中,并由 ScriptResource.axd 處理程序來輸出,開發人員也可以利用 ClientScriptManager(Page.ClientScript 屬性)中的方法來添加腳本到網頁程序中,常用的方法有:
- ClientScriptManager.RegisterClientScriptBlock():注冊客戶端腳本區塊 (script block)。
- ClientScriptManager.RegisterStartupScript():注冊在起始時運行的腳本。
- ClientScriptManager.RegisterOnSubmitStatement():注冊在處理窗體發送時要運行的腳本。
- ClientScriptManager.RegisterClientScriptInclude():注冊由外部文件 (.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 還提供了兩種可以由開發人員自行發展處理模型的模塊,一種是HTTP Handler,另一種則是HTTP Module。
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,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的ASP.NET处理架构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 白话数字签名(番外篇)----签名EXE
- 下一篇: [设计模式]原型模式