HttpModule和Http Handler (比較與區別)

HttpModule和Http Handler (比較與區別)web

HttpModule概述數據庫

暫時先不考慮咱們本身實現Http Module的狀況。在.Net中,Http Module 是實現了IHttpModule接口的程序集。IHttpModule 接口自己並無什麼好大寫特寫的,由它的名字能夠看出,它不過是一個普普統統的接口而已。實際上,咱們關心的是實現了這些接口的類,若是咱們也編寫代碼實現了這個接口,那麼有什麼用途。通常來講,咱們能夠將Asp.Net中的事件分紅三個級別,最頂層是 應用程序級事件、其次是頁面級事件、最下面是控件級事件,事件的觸發分別與 應用程序週期、頁面週期、控件週期緊密相關。而 Http Module 的做用是與應用程序事件 密切相關的。編程

咱們經過Http Module在Http請求管道(Pipeline)中註冊指望對應用程序事件作出反應的方法,在相應的事件觸發的時候(好比說BeginRequest事件,它在應用程序收到一個Http請求並即將對其進行處理時觸發),便會調用Http Module註冊了的方法,實際的工做在這些方法中執行。.Net 自己已經有不少的Http Module,其中包括 表單驗證Module(FormsAuthenticationModule), Session 狀態Module(SessionStateModule),輸出緩存Module (OutputCacheModule)等。api

註冊 Http Module瀏覽器

在註冊咱們本身編寫的 Http Module 以前,先來看看Asp.Net中已經有的HttpModule。與 Http Handler相似,咱們須要打開機器上C:\WINDOWS\Microsoft.NET\Framework\ v2.0.50727\CONFIG 目錄下的 web.config 文件。找到 <httpModules/> 結點,應該能夠看到下面的內容:緩存

<httpModules>安全

<add name="OutputCache" type="System.Web.Caching.OutputCacheModule" />服務器

<add name="Session" type="System.Web.SessionState.SessionStateModule" />session

<add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" />app

<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />

<add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" />

<add name="RoleManager" type="System.Web.Security.RoleManagerModule" />

<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />

... 略

</httpModules>

咱們先從結點上看,type屬性與上一節所說的http handler結點的type屬性相似,都表明了相應的程序集。可是,與http handler 不一樣,module只提供了一個name屬性,沒有諸如 path這樣指定某一特定(或者用通配符 * 表明某一種類)文件的處理程序。這是與Module的特色相關的,咱們知道 module 是響應應用程序週期中觸發的事件,對於全部提交到aspnet_isapi.dll的請求都同樣,即使請求只是像相似http://www.tracefact.net/images/logo.gif這樣獲取一張圖片而已(對ISAPI進行過設置之後,默認aspnet_isapi.dll不接手圖片文件)。

與Http handler相似,在這冊咱們本身的http module 時,假設類名爲ModuleDemo,位於myNameSpace命名空間下,程序集名稱爲myDll,咱們只需將myDll.dll拷貝到Bin目錄下,並在站點的 web.config 文件 system.web 結點下建立 httpModules 結點:

<system.web>

<httpModules>

<add name="CustomModuleName" type="myNameSpace.ModuleDemo, myDll"/>

</httpModules>

</system.web>

type屬性由分號「,」分爲兩部分,前面是命名空間及類名,也就是類型名;後面是程序集名。若是咱們將代碼建立在App_Code目錄中,則不須要再指定程序集名。

name屬性由咱們本身命名,不必定與類名相同,此處我將它命名爲「CustomModuleName」。咱們能夠經過應用程序(HttpApplication)的Modules屬性獲取HttpModuleCollection集合,而後經過name屬性,進一步獲取HttpModule對象。

經過name屬性,咱們還能夠在global.asax中文件中編寫自定義HttpModule暴露出的事件的處理程序,它採用的格式是:void ModuleName_EventName(object sender, EventArgs e)。咱們將在後面作更詳細介紹。

Asp.Net 內置的 Http Modules

下面這張表格列出了C:\WINDOWS\Microsoft.NET\Framework\ v2.0.50727\CONFIG下的Web.Config中的 Asp.Net 內置的Http Modules 及其主要做用。

名稱 類型 功能

OutputCache System.Web.Caching.OutputCacheModule 頁面級輸出緩存

Session System.Web.SessionState.SessionStateModule Session狀態管理

WindowsAuthentication System.Web.Security.WindowsAuthenticationModule 用集成Windows身份驗證進行客戶端驗證

FormsAuthentication System.Web.Security.FormsAuthenticationModule 用基於Cookie的窗體身份驗證進行客戶端身份驗證

PassportAuthentication System.Web.Security.PassportAuthenticationModule 用MS護照進行客戶身份驗證

RoleManager System.Web.Security.RoleManagerModule 管理當前用戶角色

UrlAuthorization System.Web.Security.UrlAuthorizationModule 判斷用戶是否被受權訪問某一URL

FileAuthorization System.Web.Security.FileAuthorizationModule 判斷用戶是否被受權訪問某一資源

AnonymousIdentification System.Web.Security.AnonymousIdentificationModule 管理Asp.Net應用程序中的匿名訪問

Profile System.Web.Profile.ProfileModule 管理用戶檔案文件的創立 及相關事件

ErrorHandlerModule System.Web.Mobile.ErrorHandlerModule 捕捉異常,格式化錯誤提示字符,傳遞給客戶端程序

咱們將在後面用編程的方式來查看它。

IHttpModule接口

看了這麼多理論知識,本節將開始動手寫點程序,實現本身的Http Module。咱們首先須要看下IHttpModule 接口,它包括下面兩個方法:

public void Init(HttpApplication context);

public void Dispose();

Init():這個方法接受一個HttpApplication對象,HttpApplication表明了當前的應用程序,咱們須要在這個方法內註冊 HttpApplication對象暴露給客戶端的事件。可見,這個方法僅僅是用來對事件進行註冊,而實際的事件處理程序,須要咱們另外寫方法。

整個過程很好理解:

1.當站點第一個資源被訪問的時候,Asp.Net會建立HttpApplication類的實例,它表明着站點應用程序,同時會建立全部在Web.Config中註冊過的Module實例。

2.在建立Module實例的時候會調用Module的Init()方法。

3.在Init()方法內,對想要做出響應的HttpApplication暴露出的事件進行註冊。(僅僅進行方法的簡單註冊,實際的方法須要另寫)。

4.HttpApplication在其應用程序週期中觸發各種事件。

5.觸發事件的時候調用Module在其Init()方法中註冊過的方法。

NOTE:若是你不瞭解事件註冊等相關內容,請參閱 C#中的委託與事件 一文。

Dispose():它能夠在進行垃圾回收以前進行一些清理工做。

綜上所述:實現一個 IHttpModule 的模板通常是這樣的:

public class ModuleDemo:IHttpModule

{

public void Init(HttpApplication context) {

// 註冊HttpApplication應用程序 BeginRequest 事件

// 也能夠是其餘任何HttpApplication暴露出的事件

context.BeginRequest += new EventHandler(context_BeginRequest);

}

void context_BeginRequest(object sender, EventArgs e) {

HttpApplication application = (HttpApplication)sender;

HttpContext context = application.Context;

// 作些實際的工做,HttpContext對象都得到了,剩下的基本能夠自由發揮了

}

public void Dispose() {

}

}

經過Http Module向Http請求輸出流中寫入文字

本例中,咱們僅用BeginRequest事件和 EndRequest 事件對 Http Module 的使用做以說明。咱們經過這個範例,瞭解 Http Module 基本的使用方法。

首先,請建立一個新的站點,在App_Code目錄中添加類文件: ModuleDemo.cs:

public class ModuleDemo:IHttpModule

{

// Init方法僅用於給指望的事件註冊方法

public void Init(HttpApplication context) {

context.BeginRequest += new EventHandler(context_BeginRequest);

context.EndRequest += new EventHandler(context_EndRequest);

}

// 處理BeginRequest 事件的實際代碼

void context_BeginRequest(object sender, EventArgs e) {

HttpApplication application = (HttpApplication)sender;

HttpContext context = application.Context;

context.Response.Write("<h1 style='color:#00f'>來自HttpModule 的處理,請求到達</h1><hr>");

}

// 處理EndRequest 事件的實際代碼

void context_EndRequest(object sender, EventArgs e) {

HttpApplication application = (HttpApplication)sender;

HttpContext context = application.Context;

context.Response.Write("<hr><h1 style='color:#f00'>來自HttpModule的處理,請求結束</h1>");

}

public void Dispose() {

}

}

上面的代碼很簡單,它註冊了 HttpApplication實例的 BeginRequest 事件 和 EndRequest事件,事件處理方法的做用僅僅是在http請求開始和結束的時候,給http請求的輸入流中分別寫入不一樣的內容。

接下來在 Web.config 的 System.web 結點中寫入如下內容:

<system.web>

<httpModules>

<add name="MyModule" type="ModuleDemo" />

</httpModules>

</system.web>

而後,打開創建站點時自動建立的 Default.aspx文件,在裏面打幾個字,爲了作區分,我輸入的是:位於.aspx頁面上的文字。而後,咱們在瀏覽器中打開它,應該會看到像這樣:

而後咱們再新建一個 Default2.aspx,在瀏覽器中瀏覽,能夠看到,兩個頁面的效果相同。這說明對於不一樣的兩個文件,http Module都起了做用,可見它確實是位於應用程序級,而非頁面級。

如今,咱們再打開站點中的一張圖片文件,發現顯示出的是一個紅叉叉,爲什呢?由於Http Module 針對是http 請求,而不是某個或某一類文件,因此當請求一張圖片的時候,咱們編寫的http Module依然會起做用,將文字插入到二進制圖片中,破壞了文件格式,天然只能顯示紅叉叉了。

NOTE:若是你發現你的圖片顯示正常,請不要驚訝,事情是這樣的:回想一下第一節咱們討論到的,對於圖片文件,由IIS直接處理,並不會交由aspnet_isapi.dll,因此,Module沒法捕獲對於圖片類型文件的請求。解決方法就是在IIS中進行設置一下。

這裏須要提請注意的是:若是你使用Vs2005自帶的Local Server,那麼你無需對IIS進行設置,全部的不論圖片仍是任何文件類型,都會交由aspnet_isapi.dll處理。

遍歷Http Module集合

如今,咱們經過遍歷 HttpModuleCollection 集合來查看註冊給應用程序的全部 Http Module 的名稱。

新建一個文件 RegisteredModules.aspx,在代碼後置文件中添加以下方法:

private string ShowModules() {

HttpApplication app = Context.ApplicationInstance; //獲取當前上下文的HttpApplication環境

HttpModuleCollection moduleCollection = app.Modules; //獲取全部Module集合

// 獲取全部的 Module 名稱

string[] moduleNames = moduleCollection.AllKeys;

System.Text.StringBuilder results = new System.Text.StringBuilder(); //遍歷結果集

foreach (string name in moduleNames) {

// 得到Module名稱

results.Append("<b style='color:#800800'>名稱:" + name + "</b><br />");

// 得到Module類型

results.Append("類型:" + moduleCollection[name].ToString() + "<br />");

}

return results.ToString();

}

而後在Page_Load方法中輸出一下:

protected void Page_Load(object sender, EventArgs e)

{

Response.Write(ShowModules());

}

咱們應該能夠看到下面這樣的畫面:

與以前列出的那張表格比較一下,能夠看出是幾乎徹底一致的(多了一個DefaultAuthentication)。另外注意上圖的倒數第四行,那不是咱們本身定義的Module麼?name爲MyModule,類型爲ModuleDemo。

Global.asax文件與 Http Module

早在asp時代,你們就知道這個文件了。它主要用於放置對於 應用程序事件或者 Session事件的響應程序。你們熟悉的有Application_Start、Application_End、Session_Start、Session_End 等。

在asp.net中,Glabal不只能夠註冊應用程序和Session事件,還能夠註冊Http Module暴露出的事件;不只能夠註冊系統Module的事件,也能夠註冊咱們本身義的Module暴露出的事件。在具體介紹以前,這裏須要首先注意兩點:

1.在每處理一個Http請求時,應用程序事件都會觸發一遍,可是Application_Start和 Application_End 例外,它僅在第一個資源文件被訪問時被觸發。

2.Http Module沒法註冊和響應Session事件,對於Session_Start 和 Session_End,只能經過Glabal.asax來處理。

好了,咱們如今修改以前 ModuleDemo 範例程序,給它像下面這樣給它添加一個事件(爲了使程序簡潔一些,我作了簡化):

public class ModuleDemo : IHttpModule {

// 聲明一個事件

public event EventHandler ExposedEvent;

// Init方法僅用於給指望的事件註冊方法

public void Init(HttpApplication context) {

context.BeginRequest += new EventHandler(context_BeginRequest);

}

// 處理BeginRequest 事件的實際代碼

void context_BeginRequest(object sender, EventArgs e) {

HttpApplication application = (HttpApplication)sender;

HttpContext context = application.Context;

context.Response.Write("<h3 style='color:#00f'>來自HttpModule的處理,請求到達</h3><hr>");

OnExposedEvent(new EventArgs()); // 調用方法

}

protected override void OnExposedEvent(EventArgs e) {

if (ExposedEvent != null) // 若是Global中有註冊

ExposedEvent(this, e); // 調用註冊了的方法

}

public void Dispose() {

}

}

接下來,咱們在站點中建立一個 Global.asax 文件,在裏面添加以下代碼,注意到格式是:void 模塊名_事件名(object sender, EventArgs e)。

void MyModule_ExposedEvent(object sender, EventArgs e)

{

Response.Write("<h3 style='color:#800800'>來自 Global.asax 的文字</h2>");

}

如今,咱們打開以前的頁面,應該能夠見到這樣,可見,咱們成功的將 Glabal.asax文件與咱們本身定義的Http Module所暴露出的事件 ExposedEvent 聯繫到了一塊兒:

總結

本文簡單地介紹了什麼是Http Module。咱們首先了解了Http Module的做用,而後查看了Asp.Net 內置的Module,接着咱們介紹了IHttpModule接口,並經過了一個簡單的範例實現了此接口,最後咱們討論了 Http Module與 Global.asax 文件的聯繫。

本文僅僅是對IHttpModule做以簡單介紹,對其更多的實際應用,會在後續文章中補充。

但願這篇文章能給你帶來幫助!

IHttpHandler 概述

可能和我同樣,不少Asp.Net開發人員都有過Asp的背景,以致於咱們在開發程序的時候,一般都是在「頁面級」上思考,也就是說咱們如今正在作的這個頁面應該有什麼樣的功能,是進行一個問卷調查仍是一個數據庫查詢等等。而不多在「請求級」思考,考慮有沒有辦法來經過編碼的方式來操控一個Http請求。

實際上,Framework提供了一系列的接口和類,容許你對於Http請求進行編程,而實現這一操做的一個主要的接口,就是 IHttpHandler(另外一個是IHttpModule)。

應該還記得第一節中咱們提到過 ISAPI,它根據文件名後綴把不一樣的請求轉交給不一樣的處理程序。可是仔細看看就會發現:幾乎一大半的文件都交給 aspnet_isapi.dll 去處理了。很明顯,aspnet_isapi.dll 不可能對每種文件採用同一種方式處理,那麼 aspnet_isapi.dll 是如何更進一步處理不一樣的文件,交由誰去處理呢?爲了搞清楚這個問題,咱們須要打開機器上C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\ 目錄下的web.config 文件。

NOTE:我查閱了不少資料,都說是在 machine.config 中,但實際上 v2.0.50727 下的machine.config中httpHandlers結點是這樣的:<httpHandlers />,並無給出詳細的處理程序,在Web.config中才能看到。而v1.1.4322 下的machine.config中卻有。

找到httpHandlers結點,應該能夠看到以下這樣的代碼(作了省略):

<httpHandlers>

... ... //略

<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True" /><add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True" />

<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True" />

<add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />

<add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />

<add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />

<add path="*.cs" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" />

<add path="*" verb="GET,HEAD,POST" type="System.Web.DefaultHttpHandler" validate="True" />

... ... //略

</httpHandlers>

能夠看到,在<httpHandlers>結點中將不一樣的文件類型映射給不一樣的Handler去處理,對於.aspx來講,是由System.Web.UI.PageHandlerFactory來處理。而對於.cs來講,是由System.Web.HttpForbiddenHandler 處理,從ForbiddenHandler名字中出現的Forbidden (翻譯過來是「禁止」)能夠看出,這個Handler能夠避免咱們的源碼被看到。

NOTE:System.Web.UI.PageHandlerFactory 是一個IHttpHandlerFactory,而不是一個單一的HttpHandler,IHttpHandlerFactory用來作什麼後面會說明。

上面列出的是.Net Framework在處理Http請求時的所採用的默認Handler。而若是咱們要用編程的方式來操控一個Http請求,咱們就須要實現IHttpHandler接口,來定製咱們本身的需求。

IHttpHandler的定義是這樣的:

public interface IHttpHandler{

void ProcessRequest(HttpContext context);

bool IsReusable { get; }

}

由上面能夠看出IHttpHandler要求實現一個方法和一個屬性。其中 ProcessRequest,從名字(處理請求)看就知道這裏應該放置咱們處理請求的主要代碼。

IsReusable屬性,MSDN上是這樣解釋的:獲取一個值,該值指示其餘請求是否可使用 IHttpHandler 實例。也就是說後繼的Http請求是否是能夠繼續使用實現了該接口的類的實例,通常來講,我把它設置成true。

那麼實現此接口的類形式應該是這樣的:

public class CustomHandler : IHttpHandler{

public void ProcessRequest(HttpContext context) {

// 處理請求的代碼

}

public bool IsReusable {

get { return true; }

}

}

而爲了能使用這個自定義的HttpHandler,咱們須要在應用程序目錄下的Web.config中註冊它。

<system.web>

<httpHandlers>

<add path="*.jpg" verb="*" type="MyNameSpace.MyClass, MyDllName" />

</httpHandlers>

</system.web>

應該發現這與以前在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\目錄下web.config中看到的幾乎徹底同樣。這裏,path指的是請求的文件名稱,可使用通配符擴大範圍,也能夠明確指定這個handler僅用於處理某個特定的文件(好比說:filename.aspx)的請求。verb指的是請求此文件的方式,能夠是post或get,用*表明全部訪問方式。type屬性由「,」分隔成兩部分,第一部分是實現了接口的類名,第二部分是位於Bin目錄下的編譯過的程序集名稱。

NOTE:若是你新建一個項目,而且在項目下建立HandlerTest.cs,而後讓站點引用該項目,那麼在生成解決方案的時候會自動將編譯好的.dll文件添到Bin目錄中。

NOTE:MyDll只寫程序集名,不要加後面的.dll。

使用HttpHandler實現圖片防盜鏈

有了以前這麼多的準備知識,實現如今的目標就容易得多了:

NOTE:這個例子,以及下面的一個例子均來自於《Maximizing ASP.NET Real World, Object-Oriented Development》一書:

Step.1:建立文件 CustomHandler.cs,代碼以下:

using System;

using System.Web;

namespace CustomHandler{

public class JpgHandler : IHttpHandler{

public void ProcessRequest(HttpContext context){

// 獲取文件服務器端物理路徑

string FileName = context.Server.MapPath(context.Request.FilePath);

// 若是UrlReferrer爲空,則顯示一張默認的禁止盜鏈的圖片

if (context.Request.UrlReferrer.Host == null){

context.Response.ContentType = "image/JPEG";

context.Response.WriteFile("/error.jpg");

}else{

// 若是 UrlReferrer中不包含本身站點主機域名,則顯示一張默認的禁止盜鏈的圖片

if (context.Request.UrlReferrer.Host.IndexOf("yourdomain.com") > 0){

context.Response.ContentType = "image/JPEG";

context.Response.WriteFile(FileName);

}else{

context.Response.ContentType = "image/JPEG";

context.Response.WriteFile("/error.jpg");

}

}

}

public bool IsReusable{

get{ return true; }

}

}

}

Step.2 編譯這個文件

csc /t:library /r:System.Web.dll CustomHandler.cs

Step.3 將編譯好的 CustomHandler.dll 拷貝到站點的 Bin 目錄下。

Step.4 在Web.Config 中註冊這個Handler。

<system.web>

<httpHandlers>

<add path="*.jpg" verb="*" type="CustomHandler.JpgHandler, CustomHandler" />

</httpHandlers>

</system.web>

OK,諸位能夠按步驟自行測試一下,這裏就不贅述了。

經過IhttpHandler實現圖片驗證碼

也能夠在一個.ashx文件中實現IHttpHandler,而不是採用這種提早編譯的方式。

Step.1 打開Vs2005,「添加新項」,「通常處理程序」。新建文件後,VS會自動在文件中添加以下的代碼:

<%@ WebHandler Language="C#" Class="Handler" %>

using System;

using System.Web;

public class Handler : IHttpHandler {

public void ProcessRequest (HttpContext context) {

context.Response.ContentType = "text/plain";

context.Response.Write("Hello World");

}

public bool IsReusable {

get {

return false;

}

}

}

Step.2 將代碼改寫成以下所示:

<%@ WebHandler Language="C#" Class="Handler" %>

using System;

using System.Drawing;

using System.Drawing.Imaging;

using System.Text;

using System.Web;

using System.Web.SessionState;

public class Handler : IHttpHandler, IRequiresSessionState {

public void ProcessRequest(HttpContext context) {

context.Response.ContentType = "image/gif";

//創建Bitmap對象,繪圖

Bitmap basemap = new Bitmap(200, 60);

Graphics graph = Graphics.FromImage(basemap);

graph.FillRectangle(new SolidBrush(Color.White), 0, 0, 200, 60);

Font font = new Font(FontFamily.GenericSerif, 48, FontStyle.Bold, GraphicsUnit.Pixel);

Random r = new Random();

string letters = "ABCDEFGHIJKLMNPQRSTUVWXYZ";

string letter;

StringBuilder s = new StringBuilder();

//添加隨機的五個字母

for (int x = 0; x < 5; x++) {

letter = letters.Substring(r.Next(0, letters.Length - 1), 1);

s.Append(letter);

graph.DrawString(letter, font, new SolidBrush(Color.Black), x * 38, r.Next(0, 15));

}

//混淆背景

Pen linePen = new Pen(new SolidBrush(Color.Black), 2);

for (int x = 0; x < 6; x++)

graph.DrawLine(linePen, new Point(r.Next(0, 199), r.Next(0, 59)), new Point(r.Next(0, 199), r.Next(0, 59)));

//將圖片保存到輸出流中

basemap.Save(context.Response.OutputStream, ImageFormat.Gif);

context.Session["CheckCode"] = s.ToString(); //若是沒有實現IRequiresSessionState,則這裏會出錯,也沒法生成圖片

context.Response.End();

}

public bool IsReusable {

get { return true; }

}

}

須要特別注意的是,Handler類不只須要實現 IHttpHandler接口(這個顯然),爲了在這個Handler類中使用SessionState,還須要實現IRequiresSessionState接口,對於這個接口,MSDN的解釋是這樣的:Specifies that the target HTTP handler requires read and write access to session-state values. This is a marker interface and has no methods.(翻譯過來是:指定當前Http Handler須要對SessionState值的讀寫訪問權。這是一個標記接口,沒有任何方法)。

而實際上,IRequiresSessionState的接口定義是這樣的:

public interface IRequiresSessionState{}

可見,這個接口沒有任何須要實現的方法或屬性,你們只要記得:若是想在HttpHandler中使用SessionState,必須實現這個接口,實際上也就是在類的標頭將這個接口加進去。

Step.3 新建一個ImageCode.aspx頁面,在HTML代碼中寫下:

<img src="Handler.ashx" alt="圖片驗證碼" />

OK,在瀏覽器中打開ImageCode.aspx,應該能夠看到以下所示:

利用HttpHandler建立自定義後綴Rss源

RSS現在已經能夠說是隨處可見,而RSS的實現方式,一般是在一個.aspx的CodeBehind文件中寫一個XML文件,而後加載到Response的OutputStream中, Rss源一般是Rss.aspx這種形式的。經過第一章學到的ISAPI的知識,再結合本章學到的關於HttpHandler的知識,很容易想到:咱們能夠自定一個以 .rss 做爲後綴名的文件來實現 Rss 源,好比說Article.rss。如今咱們就一步步來實現它:

NOTE:關於RSS的更多內容,能夠參閱我編譯的 在Web站點中建立和使用RSS源。本文再也不解釋Rss是什麼,如何建立Rss源,爲了文章的獨立性,僅給出建立過程。

Step.1 建立範例數據庫

Create Table RssSample

(

SampleId Int Identity(1,1) Not Null,

Title Varchar(100) Not Null Constraint uq_Title Unique,

Author Varchar(50) Not Null,

PubDate DateTime Not Null Default GetDate(),

[Description] Varchar(500) Not Null,

Link Varchar(150) Not Null

Constraint pk_RssSample Primary Key(SampleId)

)

-- 插入範例數據

Insert Into RssSample(Title, Author, [Description], Link)

Values('標題1', '做者1', '文章摘要1', 'http://127.0.0.1/#' )

-- 省略 ....

Step.2 創建站點,在App_Code目錄下創建RssFeedsLib.cs文件。

using System;

using System.Data;

using System.Data.SqlClient;

using System.IO;

using System.Web;

using System.Xml;

using System.Text;

namespace RssFeadsLib {

public class RssGenerator {

public static string GetRSS() {

MemoryStream ms = new MemoryStream();

XmlTextWriter writer = new XmlTextWriter(ms, null);

SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=Sample;User ID=sa;Password=sa"); //修改這裏成你的數據庫鏈接

SqlCommand cmd = new SqlCommand("select * from RssSample order by pubdate desc", conn);

conn.Open();

SqlDataReader reader = cmd.ExecuteReader();

writer.WriteStartElement("rss");

writer.WriteAttributeString("version", "2.0");

writer.WriteStartElement("channel");

// Channel 下的結點靜態寫入

writer.WriteElementString("title", "TraceFact.Net 技術文章");

writer.WriteElementString("link", "http://www.tracefact.net/");

writer.WriteElementString("description", "Dedicated to asp.net...");

writer.WriteElementString("copyright", "Copyright (C) 2007");

writer.WriteElementString("generator", "My RSS Generator");

// Item 結點從數據庫讀取

while (reader.Read()) {

writer.WriteStartElement("item");

writer.WriteElementString("author", reader.GetString(reader.GetOrdinal("Author")));

writer.WriteElementString("title", reader.GetString(reader.GetOrdinal("title")));

writer.WriteElementString("link", reader.GetString(reader.GetOrdinal("Link")));

writer.WriteElementString("description", reader.GetString(reader.GetOrdinal("Description")));

writer.WriteElementString("pubDate", reader.GetDateTime(reader.GetOrdinal("PubDate")).ToString(@"ddd, dd MMM yyyy 12:00:00 tt "));

writer.WriteEndElement();

}

writer.WriteEndElement();

writer.WriteEndElement();

reader.Close();

conn.Close();

writer.BaseStream.Flush();

writer.Flush();

ms.Flush();

// 將流轉換成String並返回

byte[] data = new byte[ms.Length];

ms.Seek(0, SeekOrigin.Begin);

ms.Read(data, 0, data.Length);

ms.Close();

return UTF8Encoding.UTF8.GetString(data);

}

}

}

Step.3 建立能夠處理 .rss 後綴名的 RssHandler

咱們在這個 RssFeedsLib命名空間下,再添加一個類,這個類用於處理對 .rss 後綴名文件的Http請求。

public class RSSHandler:IHttpHandler{

public bool IsReusable

{

get {return false;}

}

public void ProcessRequest(HttpContext context){

context.Response.ContentType = "text/xml";

string str = RssGenerator.GetRSS();

context.Response.Write(str);

}

}

Step.4 在Web.config中進行配置

<httpHandlers>

<add path="*.rss" type="RssFeadsLib.RSSHandler" verb="GET" />

</httpHandlers>

NOTE:由於這個類和命名空間位於App_Code中,這裏就不須要再手動編譯RssFeadsLib.cs而後將編譯好的.dll應用程序集放到Bin目錄中了。至於爲何能夠這樣,將會在 《Asp.Net 構架與安全機制 Part.5 – 頁面生存週期與編譯模型》中解釋。

Step.5 在IIS 對ISAPI進行設置。

應該還記得在Part.1中如何在IIS中設置ISAPI來進行文件與處理程序映射:

1.打開IIS,選擇本範例所用的站點,右鍵,選擇「屬性」。

2.選擇「主目錄」選項卡,點擊「配置...」按鈕。

3.點擊「添加」,設置「可執行文件」爲「C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll」,設置「擴展名」爲「.rss」,點「肯定」。

4.注意,不要勾選「檢查文件是否存在」複選框,這樣不用建立文件,只要在地址欄輸入任意以.rss後綴結尾的文件名,均會交由上面建立的Handler去處理,而無論這個文件是否存在,也無論請求的是Article.rss仍是Sample.rss。

進行了這些設置之後,如今IIS就知道如何去處理對.rss後綴名文件的請求了。

Step.6 測試範例

這個時候,隨便打開一個頁面,好比空白的Default.aspx,而後咱們在地址欄將文件改成:Article.rss(改爲abc.rss也是同樣),敲回車,應該能夠看到以下的畫面。

IHttpHandlerFactory 概述

如今假設咱們有這樣的需求,咱們不只想要處理 .rss 後綴名,還想要可以處理 .atom後綴名,假設處理atom的類命名爲AtomHandler,那麼咱們的Web.config該如何設置呢?我想應該是這樣的:

<httpHandlers>

<add path="*.rss" type="RssFeadsLib.RSSHandler" verb="GET" />

<add path="*.atom" type="RssFeadsLib.AtomHandler" verb="GET" />

</httpHandlers>

若是咱們有不少個HttpHandler分別映射不一樣後綴名的請求,這樣咱們的Web.config會變得很冗長,或者,咱們只有在程序運行時才能確切地知道使用哪一個Handler,這個時候,能夠考慮實現 IHttpHandlerFactory來完成這一過程。

IHttpHandlerFactory的定義是這樣的:

public interface IHttpHandlerFactory{

IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);

void ReleaseHandler(IHttpHandler handler);

}

可見,須要實現兩個方法,分別是 GetHandler() 和 ReleaseHandler()。

GetHandler(),返回實現了IHttpHandler接口的類的實例。

ReleaseHandler(),使得Factory能夠重複使用一個已經存在的Handler實例。

對於上面 .atom 和 .rss 的問題,咱們能夠這樣來實現 IHttpHandlerFactory接口:

class HandlerFactory:IHttpHandlerFactory{

public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated){

string path = context.Request.PhysicalPath;

if (Path.GetExtension(path) == ".rss"){

return new RSSHandler();

}

if (Path.GetExtension(path) == ".atom"){

return new ATOMHandler();

}

return null;

}

public void ReleaseHandler(IHttpHandler handler){

}

}

這時,在Web.Config 中<system.web>節點下進行以下設置便可:

<httpHandlers>

<add path="*.rss,*.atom" type=" RssFeadsLib.HandlerFactory" verb="GET" />

</httpHandlers>

可是,這不能簡化IIS中ISAPI的設置,仍是須要手動去對.rss和.atom分別設置。

總結

在本文中,咱們首先討論了aspnet_isapi.dll 如何將對不一樣後綴名文件的請求分發給相應的處理程序,如何查看Framework默認的處理程序Handler。

而後,咱們經過三個實例,圖片防盜鏈、圖片驗證碼、處理自定義後綴名請求,詳細講解了IHttpHandler的實現方法和使用過程。

最後,我向你們概要地介紹了IHttpHandlerFactory接口

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/chengfong/archive/2009/04/17/4088530.aspx

相關文章
相關標籤/搜索