ASP.NET使用管道模型(PipleLines)处理HTTP请求
大多數(shù)人認(rèn)為ASP.NET僅僅只是頁(yè)面——使用模板來(lái)創(chuàng)建HTML頁(yè)面然后返回給瀏覽器。但是這僅僅只是ASP.NET使用HTTP管道模型處理WEB程序很小的一方面。管道模型是類(lèi)似于Web Services的一種在服務(wù)器端處理ASP.NET頁(yè)面的框架技術(shù)。作為一名高級(jí)的ASP.NET的開(kāi)發(fā)者,你必須清楚管道模型是如何工作的。這篇文章就是解釋和闡述HTTP管道模型是如何處理HTTP請(qǐng)求的。
一、管道對(duì)象模型
在System.Web的命名空間中處理HTTP的請(qǐng)求主要使用管道模型。一般的管道模型的結(jié)構(gòu)如圖-1。在管道模型開(kāi)始運(yùn)行前,HTTP的請(qǐng)求首先被傳到HttpRuntime類(lèi)的一個(gè)實(shí)例中,然后這個(gè)HttpRuntime的對(duì)象開(kāi)始檢查請(qǐng)求并找出這個(gè)請(qǐng)求被發(fā)送到的那個(gè)應(yīng)用程序(在管道程序看來(lái),一個(gè)虛擬目錄就是一個(gè)應(yīng)用程序)。然后管道模型就使用一個(gè)HttpApplicationFactory對(duì)象來(lái)找出或者創(chuàng)建一個(gè)HttpApplication對(duì)象來(lái)處理這個(gè)請(qǐng)求,一個(gè)HttpApplication可以包含一系列HTTP module對(duì)象(派生自IHttpModule接口)。HTTP modules作為一個(gè)過(guò)濾器可以在HTTP請(qǐng)求和響應(yīng)信息穿過(guò)管道模型時(shí)檢查和修改這些信息的內(nèi)容。然后HttpApplication對(duì)象就使用HTTP handler factory來(lái)找出或產(chǎn)生一個(gè)HTTP handler對(duì)象。HTTP handlers是HTTP通信的最后一步,它主要用于處理請(qǐng)求信息(request)和響應(yīng)信息(response)。注:HTTP handlers和 handler factory分別派生自IHttpHandler接口和IHttpHandlerFactory接口。
?
圖-1
一個(gè)HttpApplication包括它的modules、handler在同一時(shí)刻只能處理一個(gè)Request請(qǐng)求。如果多重request請(qǐng)求同時(shí)到達(dá)一個(gè)相同的application時(shí),多重HttpApplication對(duì)象將會(huì)被使用。
管道模型使用一個(gè)HttpContext對(duì)象去描述聲明每一個(gè)成對(duì)的request/response信息。這個(gè)對(duì)象在HttpApplicaiton和handler之間來(lái)回傳遞。每一個(gè)module也能訪問(wèn)當(dāng)前的HttpContext。HttpContext對(duì)象通過(guò)屬性來(lái)描述聲明HTTP的request和response信息(分別創(chuàng)建HttpRequest類(lèi)和HttpResponse類(lèi)的對(duì)象);同樣,HttpContext對(duì)象也能通過(guò)屬性來(lái)描述聲明安全信息和每一個(gè)call、session和application。圖-2展示了部分HttpContext類(lèi)常用的屬性。
ASP.NET的HTTP管道模型是可擴(kuò)展的,你可以實(shí)現(xiàn)自己的HTTP module、handler以及handler factory。你也可以直接繼承HttpApplication類(lèi)。
?
?
?
| 屬性名 | 描述 |
| Application | 每一個(gè)application的request信息 |
| Application Instance | 正在處理request請(qǐng)求的Application對(duì)象 |
| Cache | 每一個(gè)application的緩存信息 |
| Handler | 正在處理request請(qǐng)求的Handler對(duì)象 |
| Items | 每一個(gè)request請(qǐng)求信息 |
| Request | HTTP request 信息 |
| Response | HTTP response 信息 |
| Server | Utility functions |
| Session | Per-user cross-request state |
| User | User information |
圖-2:HttpContext類(lèi)的常用屬性
?
二、管道處理模型
ASP.NET的HTTP管道程序運(yùn)行在IIS上來(lái)接收傳遞到進(jìn)程中的request請(qǐng)求(被完整地傳送到其他的web服務(wù)器上)。當(dāng)IIS接收到一個(gè)HTTP的request請(qǐng)求時(shí),它首先會(huì)通過(guò)目標(biāo)URL檢查文件的擴(kuò)展名,如果文件的名被可執(zhí)行代碼關(guān)聯(lián),IIS就會(huì)調(diào)用這些代碼來(lái)處理request請(qǐng)求。文件的擴(kuò)展名被映射成可執(zhí)行代碼存儲(chǔ)在IIS的metabase標(biāo)記中。當(dāng)ASP.NET被安裝后,它會(huì)通過(guò)一個(gè)動(dòng)態(tài)鏈接庫(kù)aspnet_isapi.dll將各種不同的文件擴(kuò)展名添加到matabase標(biāo)記中,包括.apx和.asmx。
當(dāng)IIS收到一個(gè)某一個(gè)頁(yè)面文件發(fā)送的HTTP request請(qǐng)求時(shí),它會(huì)調(diào)用aspnet_isapi.dll中的代碼:使用一個(gè)命名管道將IIS服務(wù)器上的inetinfo.exe發(fā)送來(lái)的request請(qǐng)求轉(zhuǎn)發(fā)到ASP.NET工作進(jìn)程的一個(gè)實(shí)例:aspnet_wp.exe中。(在Windows Server 2003中, IIS 6.0kernel-mode模式的HTTP listener, 允許 request請(qǐng)求不通過(guò)inetinfo.exe而直接從操作系統(tǒng)轉(zhuǎn)發(fā)到工作進(jìn)程。)工作進(jìn)程使用一個(gè)HttpRuntime類(lèi)的實(shí)例來(lái)處理request請(qǐng)求。圖-3 展示了完整的機(jī)制。
圖-3
HTTP管道程序在工作進(jìn)程的實(shí)例中處理request請(qǐng)求。默認(rèn)地,在某一時(shí)刻僅僅只能有一個(gè)工作進(jìn)程工作(如果你的web服務(wù)器有多個(gè)CPU,你可以配置管道程序使用多個(gè)工作進(jìn)程),這是一個(gè)在本地IIS上很重要的一個(gè)改變,它使用不同的工作進(jìn)程主要為了隔離不同的application程序。同時(shí)管道程序的各個(gè)工作進(jìn)程也完全地被AppDomain所隔離,你可以將AppDomain看作是進(jìn)程中的一個(gè)子進(jìn)程。管道程序向一個(gè)AppDomain中的所有虛擬目錄發(fā)送HTTP request請(qǐng)求。換句話說(shuō),每一個(gè)虛擬目錄被作為一個(gè)單獨(dú)的應(yīng)用程序?qū)Υ_@還有另外一個(gè)本地IIS值得注意的改變就是允許多個(gè)虛擬目錄成為同一個(gè)application的一部分。
?ASP.NET支持基于很多標(biāo)準(zhǔn)的循環(huán)工作進(jìn)程,這些標(biāo)準(zhǔn)包括空閑時(shí)間、requests serviced的數(shù)量、requests隊(duì)列的數(shù)量以及物理內(nèi)存的耗費(fèi)量。全局.NET配置文件和machine配置文件初始化這些數(shù)值(好象processModel的元素)。當(dāng)一個(gè)aspnet_wp.exe的實(shí)例 crosses one of these thresholds, aspnet_isapi.dll會(huì)運(yùn)行一個(gè)新的工作進(jìn)程并開(kāi)始發(fā)送request請(qǐng)求。舊的實(shí)例在它處理完request請(qǐng)求后會(huì)自動(dòng)終止。循環(huán)工作進(jìn)程會(huì)提升可靠性通過(guò)在這些進(jìn)程耗盡資源之前殺死它們。
三、HTTP Handlers
HTTP handlers 是一個(gè)繼承自IHttpHandler接口的簡(jiǎn)單類(lèi),以下是該類(lèi)的詳細(xì)代碼:
interface IHttpHandler
{
?// called to process request and generate response
?void ProcessRequest(HttpContext ctx);
?// called to see if handler can be pooled
?bool IsReuseable { get; }
}
Handlers也可以繼承自IHttpAsyncHandler接口,如果想要它們支持異步調(diào)用。
HttpApplicaiton對(duì)象會(huì)調(diào)用ProcessRequest方法,通過(guò)handler來(lái)處理當(dāng)前的HTTP請(qǐng)求和產(chǎn)生response響應(yīng)。在此期間IsReuseable屬性會(huì)被訪問(wèn)為類(lèi)測(cè)定hanlder是否可以被再使用。
圖-4的代碼實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的可以重用的HTTP句柄,它可以響應(yīng)所有的request請(qǐng)求并返回當(dāng)前的時(shí)間在一個(gè)XML標(biāo)記中。你也可以使用使用HttpContext對(duì)象的response屬性來(lái)設(shè)置response信息的MIME屬性從而輸出自己的內(nèi)容。using System; using System.Web; ? namespace Pipeline { ? ?public class TimeHandler : IHttpHandler ?{ ??? void ProcessRequest(HttpContext ctx) ??? { ????? ctx.Response.ContentType = "text/xml"; ????? ctx.Response.Write("<now>"); ????? ctx.Response.Write( ?????????????????? DateTime.Now.ToString()); ????? ctx.Response.Write("</now>"); ??? } ??? bool IsReuseable { get { return true; } } ?} }圖-4:TimeHandler
?
?
?
當(dāng)HTTP handler類(lèi)被實(shí)現(xiàn)時(shí),它一定是被配置好的。配置會(huì)分為三個(gè)階段:第一、你應(yīng)該將編譯好的代碼放到ASP.NET工作進(jìn)程能夠找到的地方。一般地,已編譯好的.NET文件(一般是dll文件)應(yīng)該位于web服務(wù)器的虛擬目錄下的bin文件夾中或位于全局編譯緩存中(GAC)。
第二步:在HTTP request請(qǐng)求到來(lái)時(shí),你應(yīng)該讓HTTP的管道程序執(zhí)行你的代碼。你可以通過(guò)在你虛擬目錄下的web.config文件中去添加<httpHandlers>標(biāo)簽。如下:
<configuration>
?<system.web>
?<httpHandlers>
?? <add verb="GET" path="*.time"
???? type="Pipeline.TimeHandler,
???? Pipeline"
?? />
?</httpHandlers>
?</system.web>
</configuration>
???以上的代碼可以作為附加的信息添加到.config的配置文件中。例如,這個(gè)web.config文件會(huì)告訴asp.net的HTTP管道程序處理所有.time文件的GET請(qǐng)求通過(guò)調(diào)用編譯文件中的Pipeline.TimeHandler類(lèi)。
最后,這些.time文件的request請(qǐng)求會(huì)被IIS轉(zhuǎn)發(fā)到aspnet_isapi.dll,以便這些請(qǐng)求可以被管道程序第一時(shí)間處理。而且這些request請(qǐng)求也會(huì)在IIS的metabase中添加一個(gè)新的文件mapping映射。不過(guò)還有更簡(jiǎn)單的方式,就是直接使用IIS管理臺(tái)將虛擬目錄的文件擴(kuò)展名映射到Application的配置對(duì)話框中。如圖-5:
?
圖-5
?
?
除了實(shí)現(xiàn)已有的客戶端handler外,你也可以寫(xiě)自己的handler factoriey。一個(gè)handler factoriey就是一個(gè)實(shí)現(xiàn)了IHttpHandlerFactory的類(lèi)。Handler factiory的配置方法和普通handlers一樣,唯一不同的是原先web.config文件中的handler類(lèi)都將被factory類(lèi)所代替。
?
四、標(biāo)準(zhǔn)Handlers
????一些高級(jí)的ASP.NET技術(shù),例如pages和Web Services都是通過(guò)頂層HTTP handler直接創(chuàng)建的。以下是通過(guò).config文件來(lái)配置<httpHandlers>部分:
<httpHandlers> entries:
<httpHandlers>
?<add verb="*" path="*.ashx"
?type="System.Web.UI.SimpleHandlerFactory"
?/>
?<add verb="*" path="*.aspx"
??? type="System.Web.UI.PageHandlerFactory"
?? />
?? <add verb="*" path="*.asmx"
??? type="System.Web.Services.Protocols.
??? WebServiceHandlerFactory ... "
?? />
?</httpHandlers>
????第一個(gè)實(shí)體映射擴(kuò)展名為.ashx的文件到SimpleHandlerFactory類(lèi),使得一個(gè)HTTP handler factory知道如何從.ashx源文件中安裝、編譯和執(zhí)行一個(gè)IHttpHandler。然后結(jié)果對(duì)象就可以被HTTP管道程序直接使用。
?? ?圖-6展示了使用.ashx文件重寫(xiě)的一個(gè)TimeHandler例子。@WebHandler部分告訴SimpleHandlerFactory Http handler類(lèi)的名字在源代碼編譯后。這么做最大的好處就在它的配置非常簡(jiǎn)單:你只需要將所有的.ashx文件拷貝到虛擬目錄下,而不需要再創(chuàng)建或修改web.config文件或在.NET安裝完后再更新IIS。
<%@ WebHandler language="C#" ??? class="Pipeline.TimeHandler" %> ? using System; using System.Web; ? namespace Pipeline { ? ?public class TimeHandler : IHttpHandler ?{ ??? void ProcessRequest(HttpContext ctx) ??? { ????? // set response message MIME type ????? ctx.Response.ContentType = "text/xml"; ????? // write response message body ????? ctx.Response.Write("<now>"); ????? ctx.Response.Write( ?????????????????? DateTime.Now.ToString()); ????? ctx.Response.Write("</now>"); ??? } ??? bool IsReuseable { get { return true; } } ?} }圖-6
?
第二個(gè)<httpHandlers>部分的實(shí)體將.aspx文件擴(kuò)展名映射到PageHandlerFactory類(lèi),主要為了讓HTTP handler factory知道如何將.aspx的源代碼編譯成一個(gè)System.Web.UI.Page-derived類(lèi)。這個(gè)Page類(lèi)實(shí)現(xiàn)了IHttpHandler借口,因此最終對(duì)象可以被HTTP管道程序直接使用。
第三個(gè)實(shí)體將.asmx的擴(kuò)展名映射到WebServiceHandlerFactory類(lèi),這么做主要為了讓一個(gè)HTTP handler factory知道如何將一個(gè).asmx文件中的源代碼編譯并實(shí)例化。然后它會(huì)綁定一個(gè)標(biāo)準(zhǔn)的HTTP handler(默認(rèn)的為SyncSessionlessHandler)實(shí)例并使用反射機(jī)制將SOAP信息轉(zhuǎn)化成方法的調(diào)用參數(shù)。最后,最終對(duì)象就可以被HTTP管道程序直接使用了。
???這里需要值得注意的是PageHandlerFactory、WebServiceHandlerFactory和SimpleHandlerFactory類(lèi)并不能在每一個(gè)request請(qǐng)求上都編譯.aspx、.asmx和.ashx文件。作為替代,這些編譯好的代碼會(huì)被緩存在ASP.NET安裝目錄下的臨時(shí)文件中。并且當(dāng)源代碼改變時(shí),這些代碼僅僅只會(huì)被編譯一次。
?
五、HTTP Modules
????HTTP handlers是HTTP通信的最終部分。Handler類(lèi)的實(shí)例專(zhuān)門(mén)用來(lái)接收HTTP請(qǐng)求并產(chǎn)生response響應(yīng)。HTTP modules作為過(guò)濾器在request和response信息穿過(guò)管道程序時(shí)處理它們(可以是檢查并修改這些信息的內(nèi)容)。管道程序可以用這些HTTP modules特別安全地實(shí)現(xiàn)自己的底層處理程序。
HTTP modules 是實(shí)現(xiàn)IHttpModule接口的簡(jiǎn)單類(lèi):
interface IHttpModule
{
?// called to attach module to app events
?void Init(HttpApplication app);
?// called to clean up
?void Dispose()
}
當(dāng)module被第一次創(chuàng)建時(shí),Init方法會(huì)被HttpApplication對(duì)象調(diào)用,它可以通過(guò)HttpApplication對(duì)象將一個(gè)或多個(gè)事件handlers綁定到事件上。
圖-7的代碼展示了一個(gè)HTTP module如何處理HttpApplication對(duì)象的BeginRequest和EndRequest事件。在這個(gè)例子中,Init方法使用了常見(jiàn)的.NET技術(shù)將module的OnBeginRequst和OnEndRequest作為事件句柄綁定到HttpApplication對(duì)象上。OnBeginRequest主要作用是獲取存儲(chǔ)當(dāng)前時(shí)間并將時(shí)間存放到變量start中。而OnEndRequest主要作用是計(jì)算OnBeginRequest和OnEndRequest之間的運(yùn)行時(shí)間差并將這段時(shí)間添加到客戶端HTTP header中。
?
OnEndRequest方法的最大優(yōu)勢(shì)在于第一個(gè)參數(shù)實(shí)際上傳遞的module綁定的HttpApplication對(duì)象。并且當(dāng)前的信息會(huì)做為一個(gè)HttpApplication對(duì)象的屬性(Http-Context)被OnEndRequest方法使用。
using System; using System.Web; ? namespace Pipeline { ? ?public class ElapsedTimeModule : IHttpModule ?{ ??? DateTime start; ??? public void Init(HttpApplication app) ??? { ????? // register for pipeline events ????? app.BeginRequest += ????????? new EventHandler(this.OnBeginRequest); ????? app.EndRequest += ????????? new EventHandler(this.OnEndRequest); ??? } ??? public void Dispose() {} ? ??? public void OnBeginRequest(object o, ?????????????????????????????? EventArgs args) ??? { ????? // record time when request started ????? start = DateTime.Now; ??? } ? ??? public void OnEndRequest(object o, ???????????????????????????? EventArgs args) ??? { ????? // measure elapsed time ????? TimeSpan elapsed = ????????????? DateTime.Now - start; ? ????? // get access to app and context ????? HttpApplication app = ????????????? (HttpApplication) o; ????? HttpContext ctx = app.Context; ? ????? // add custom header to HTTP response ????? ctx.Response.AppendHeader( ?????????????????? "ElapsedTime", ?????????????????? elapsed.ToString()); ??? } ?} }圖-7
在一個(gè)HTTP module類(lèi)被實(shí)現(xiàn)和使用之間,必須對(duì)它做一定的配置。配置的步驟包括兩步。首先你應(yīng)該將編譯好的module代碼放到web服務(wù)器上的站點(diǎn)目錄下的bin文件夾中以至于ASP.NET的工作進(jìn)程能夠找到它。
??? 然后你應(yīng)該在你的web.config文件中添加<httpModules>部分,如下:
<configuration>
?<system.web>
?<httpModules>
?? <add
??? name="Elapsed"
??? type="Pipeline.ElapsedTimeModule, Pipeline"
?? />
?</httpModules>
?</system.web>
</configuration>
???這個(gè)例子中,web.config文件會(huì)告訴ASP.NET的HTTP管道程序?qū)ipeline.ElapsedTimeModule綁定到每一個(gè)HttpApplication對(duì)象用來(lái)處理這個(gè)虛擬目錄下的service請(qǐng)求。
總結(jié)
以上是生活随笔為你收集整理的ASP.NET使用管道模型(PipleLines)处理HTTP请求的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Redis与关系型数据库的同步问题
- 下一篇: 浦发信用卡小浦闪用是什么?怎么样?