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