是否想學(xué)習(xí)HTTP處理程序編程呢?好吧,第一步工作是熟悉IHttpHandler接口。HTTP處理程序只不過是實(shí)現(xiàn)該接口的托管類。更確切地講,同步HTTP處理程序?qū)崿F(xiàn)IHttpHandler接口;而異步HTTP處理程序?qū)崿F(xiàn)IHttpAsyncHandler接口。讓我們先看看同步處理程序。
IHttpHandler接口的合同定義了HTTP處理程序以同步方式處理一個(gè)HTTP請(qǐng)求需要采取的行動(dòng)。
1. IHttpHandler接口的成員
IHttpHandler接口只定義了兩個(gè)成員:ProcessRequest和IsReusable,如表2.1所示。ProcessRequest是一個(gè)方法,而IsReusable是一個(gè)布爾邏輯屬性。
表2.1 IHttpHandler接口的成員
成 員 |
描 述 |
IsReusable |
該屬性獲得一個(gè)布爾值,指示另一個(gè)請(qǐng)求是否可以使用該HTTP處理程序的實(shí)例 |
ProcessRequest |
該方法處理HTTP請(qǐng)求 |
Page類上的IsReusable屬性返回false,表示需要該HTTP請(qǐng)求的新實(shí)例來服務(wù)一個(gè)頁面請(qǐng)求。通常我們使它在所有情況下都返回false,并根據(jù)請(qǐng)求負(fù)荷的不同而要求它做一些有意義的處理。那些被用作篩選特殊請(qǐng)求的簡單屏障的處理程序可以將IsReusable設(shè)置為true,以節(jié)省一些CPU周期。稍后我將用一個(gè)具體的實(shí)例來說明這一點(diǎn)。
ProcessRequest方法具有如下簽名:
void ProcessRequest(HttpContext context);
它以請(qǐng)求的上下文作為輸入,并確保該請(qǐng)求得到服務(wù)。在同步處理程序的情況下,當(dāng)ProcessRequest返回時(shí),準(zhǔn)備把輸出發(fā)到客戶端。
2. 一個(gè)簡單的HTTP處理程序
再次強(qiáng)調(diào),HTTP處理程序只是一個(gè)實(shí)現(xiàn)了IHttpHandler接口的類。請(qǐng)求的輸出是在ProcessRequest方法中建立的,如下面的代碼所示:
using System.Web;
namespace ProAspNet20.Advanced.CS.Components
{
public class SimpleHandler : IHttpHandler
{
// Override the ProcessRequest method
public void ProcessRequest(HttpContext context)
{
context.Response.Write("<H1>Hello, I'm an HTTP handler</H1>");
}
// Override the IsReusable property
public bool IsReusable
{
get { return true; }
}
}
}
我們需要一個(gè)能夠調(diào)用該處理程序的入口點(diǎn)。在此上下文中,該處理程序代碼的入口點(diǎn)只不過是一個(gè)HTTP終點(diǎn)——即,一個(gè)公共的URL。該URL必須有一個(gè)惟一的名稱,使IIS和ASP.NET運(yùn)行庫能夠把它映射到該代碼。注冊(cè)時(shí),HTTP處理程序和Web服務(wù)器資源之間的映射是通過web.config文件建立的。
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="myHandler.aspx"
type="ProAspNet20.Advanced.CS.Components.SimpleHandler" />
</httpHandlers>
</system.web>
</configuration>
<httpHandlers>節(jié)列出了當(dāng)前應(yīng)用程序可用的處理程序。這些設(shè)置指示,對(duì)myHandler.aspx終點(diǎn)的任何輸入請(qǐng)求,由SimpleHandler處理程序負(fù)責(zé)處理。要注意的是,myHandler.aspx URL不必是服務(wù)器上的物理資源;它只是一個(gè)公共資源標(biāo)識(shí)符。type屬性引用包含該處理程序的類和程序集,它的標(biāo)準(zhǔn)格式是type[,assemly]。如果該組件在App_Code或其他保留文件夾中定義,則忽略該程序集信息。
注意 如果在machine.config文件中輸入上述設(shè)置,則將把SimpleHandler組件注冊(cè)成可以從服務(wù)器機(jī)器上托管的所有Web應(yīng)用程序內(nèi)可調(diào)用的組件。
如果調(diào)用myHandler.aspx URL,將得到如圖2.2所示的結(jié)果。
圖2.2 一個(gè)響應(yīng)myHandler.aspx請(qǐng)求的HTTP處理程序示例
這里所述的方法是使用HTTP處理程序最快、最簡單的方法,但是有關(guān)HTTP處理程序注冊(cè)的知識(shí),我們還有很多要了解并且還有很多其他選項(xiàng)可以利用?,F(xiàn)在,讓我們考慮一個(gè)更復(fù)雜的HTTP處理程序示例。
HTTP處理程序與ASP.NET頁面
我們應(yīng)當(dāng)利用HTTP處理程序資源來實(shí)現(xiàn)應(yīng)用程序特有的功能,它們需要比常規(guī)的Web頁面被更快地處理。在任何情況下,HTTP處理程序返回一個(gè)帶有內(nèi)容類型和主體的有效的HTTP響應(yīng)。服務(wù)一個(gè).ashx請(qǐng)求,或者一個(gè)自定義處理程序托管的任何其他請(qǐng)求,可能會(huì)導(dǎo)致比服務(wù)一個(gè).aspx資源更快的代碼。ASP.NET處理一個(gè)自定義的處理程序通常更快,因?yàn)檫@不必對(duì)用戶代碼引發(fā)任何中間事件(例如,Init, Load),不必托管任何視圖狀態(tài),而且也不支持任何回發(fā)機(jī)制。大概說來,對(duì)一個(gè)自定義的HTTP處理程序的請(qǐng)求類似于對(duì).aspx資源的請(qǐng)求,其中只發(fā)生呈現(xiàn)步驟。此外,找到服務(wù)一個(gè)頁面請(qǐng)求所需的正確的HTTP處理程序可能需要更長的時(shí)間,因?yàn)檫@要牽涉到一個(gè)頁面處理程序工廠的中間對(duì)象。
這就是說,我們要記住,ASP.NET頁面只是一個(gè)HTTP處理程序——雖然是一個(gè)非常復(fù)雜而高級(jí)的HTTP處理程序。底層的處理機(jī)制完全相同。如果說滿足某種特定需要的自定義的HTTP處理程序通常比頁面更快,這是因?yàn)樗鼈兺ǔJ菫榱酥苯拥玫浇o定結(jié)果而實(shí)現(xiàn)的。例如,假設(shè)我們需要顯示從一個(gè)數(shù)據(jù)庫中取出來的一個(gè)圖像——這是我們將在第9章中詳細(xì)討論的一個(gè)主題,我們?nèi)匀恍枰獙⒁粋€(gè)Image控件綁定到一個(gè)服務(wù)合適的MIME類型的URL。該URL應(yīng)當(dāng)是一個(gè)頁面嗎?它當(dāng)然可以是頁面;但是,如果使用一個(gè)自定義的HTTP處理程序,通常會(huì)處理得更快。
ASP.NET頁面是一個(gè)復(fù)雜對(duì)象,并由一個(gè)自定義的而且必定是復(fù)雜的HTTP處理程序(Page類)提供服務(wù)。就服務(wù)自定義資源而言,一定要使用一個(gè)合適的處理程序,只包
含必需的智能和復(fù)雜度。為了說明這一點(diǎn),假設(shè)要運(yùn)行一個(gè)查詢并提供一個(gè)數(shù)據(jù)庫中存儲(chǔ)的一個(gè)圖像的字節(jié),我們不需要任何視圖狀態(tài)和回發(fā)管理,也不需要向該應(yīng)用程序激發(fā)事件。
應(yīng)當(dāng)使用一般的.ashx資源,還是使用一個(gè)自定義的擴(kuò)展呢?這主要取決于需要實(shí)現(xiàn)的功能。ASHX方法是為相對(duì)簡單的場景設(shè)計(jì)的,其中幾乎不需要傳遞什么參數(shù)(或者根本不需要參數(shù)),并使用查詢字符串來引入它們。如果有一個(gè)自定義的文檔要處理,并且該文檔具有以非平面的或復(fù)雜的布局進(jìn)行組織的各種信息,則最好使用自定義的擴(kuò)展。