处理程序
在ASP.NET中,所有的请求都要经过HttpApplication管道的处理,但是,请求的内容确实多种多样的。因此,在HttpApplication的处理管道中,适合处理针对所有请求的通用处理,比如检查当前请求的用户身份等,并不适合直接处理情求的内容并返回处理的结果。针对不同请求的不同处理,在ASP.NET中通过各种处理程序来分别进行处理。通常情况下,根据请求的扩展名来确定适用的处理程序,根据常见的请求类型,在ASP.NET中已经与定义了许多的处理程序。
处理程序与HttpApplication的关系
在ASP.NET中,请求的真正处理是在处理程序这个环节,那么,HttpApplication的作用是什么呢?我们可以将它看作请求到达处理程序和离开处理程序的一个管道,这个管道提供了统一处理所有请求的机制,使得我们可以在请求被真正处理之前和处理之后进行预处理和处理后的工作,在有些网站处理技术中,被称为过滤器(Filter)。ASP.NET通过大量的HttpApplication事件,这些事件按照固定的次序依次处罚,使得我们可以方便地开发出针对请求不同处理环节的过滤器。
而处理程序则负责完成实际的请求处理工作,对于网站开发程序员来说,大多数的开发工作是围绕着处理程序展开的。实际上,接触到HttpApplication事件处理的时候并不多,处理程序在不同的网站开发技术中,有着不同的名称,在ASP.NET中,称为HttpHandler。
处理程序接口IHttpHandler 和 IHttpAsyncHandler
在ASP.NET中,所有的处理程序类必须实现IHttpHandler接口或者实现 IHttpAsyncHandler接口,这两个接口的区别是前者是一个同步接口,后者是一个异步处理模式的接口。这两个接口都定义在命名空间System.Web下。IHttpHandler的定义如下:
public interface IHttpHandler
{
void ProcessRequest(HttpContext context);
bool IsReusable { get; }
}
ProcessRequest是这个接口的主要方法,接受一个HttpContext类型的请求上下文对象,通过这个对象,处理程序可以得到关于处理请求所需的信息,通过这个参数的Response属性可以得到管理回应的对象,用以向客户端返回服务器处理的结果。
IsResuable属性表示当这个处理程序对象在使用之后,是否还可以被缓存起来,在以后的请求处理中再次使用,这个属性主要用来配合处理程序工厂使用。
在处理程序中使用会话
处理程序是ASP.NET网站中处理请求的基本单位,在默认情况下,处理程序中,甚至不能使用会话状态,这样可以提高网站处理的速度。对于需要读写会话状态的处理程序,必须实现一个特定的接口IRequiresSessionState,这个接口定义在命名空间System.Web.SessionState中,其中没有定义任何成员,所以实现这个接口并不需要在类中增加任何成员。与此类似,同样定义在这个命名空间下的接口 IReadOnlySessionState 也没有定义任何成员,用来标识只需读取会话状态的处理程序。
这种没有任何成员的接口,通常被称为标记接口,由于在.NET中类只有单继承,但是可以实现多个接口,所以在.NET开发早期的时候出现过一些通过标记接口来表示类的某些特征的开发技巧。但是.NET平台上提供了一个更加直接简单的技术来解决这种问题,这就是标签(Attribute),所以,这种用法昙花一现,现在很少出现。在ASP.NET开发中,这是仅有的一例。
处理程序工厂
实现了处理程序接口的类就可以被用来创建程序程序对象直接使用,如果再配合一个处理程序工厂,那么就可以实现处理程序对象的管理。比如说,创建一个处理程序对象池,就可以不同在每次使用处理程序的时候创建一个新的对象,而是可以从池中取一个现有的对象直接使用,以提高效率。
在ASP.NET中,作为处理程序工厂的类必须实现接口IHttpHandlerFactory,这个接口定义在命名空间System.Web下,其完整定义如下:
public interface IHttpHandlerFactory
{
IHttpHandler GetHandler(
HttpContext context,
string requestType,
string url,
string pathTranslated
);
void ReleaseHandler( IHttpHandler handler);
}
其中 GetHandler方法用来通过这个处理工厂获取一个处理对象,ReleaseHandler方法用来释放一个处理程序对象
注册处理程序
每一种处理程序用来处理一类的请求,不同的请求类别通过请求的扩展名来进行区分,处理程序与请求之间的匹配关系在网站的配置文件web.config中通过配置参数进行设置。system.web配置元素的子元素 httpHandlers 用来配置网站所使用的处理程序。httpHandlers元素可以包含三种子元素:add、remove、clear。
add子元素有三个必选的属性,作用如下:
verb 通过一个逗号(,)分隔的HTTP请求类型列表来表示处理请求的类型,例如GET,POST等;使用型号(*)表示处理所有类型的请求。
path 通过一个固定的URL路径或者一个使用型号(*)的通配符来匹配请求的URL,例如,使用*.aspx表示这个处理程序将处理所有扩展名为aspx的请求。
type 处理程序 的类型名称,或者是处理程序工厂的类型名称,这个类型必须是类型的全名,如果类定义在一个命名空间中,那么必须包含这个命名空间,如果定义在一个私有的应用程序集中,那么必须在类名之后,通过附加一个逗号(,)分隔的程序集名称,这个程序集的扩展名可以省略
validate为可选的属性,如果设置为false,那么ASP.NET在第一次匹配的请求调用之前将不会试图加载这个类。
例如,如果我们定义了一个处理程序类这个类定义在命名空间 MyHandler 下,名为 ValidateCodeHandler,这个类定义在私有程序集 MyHandler.dll , 用来处理GET类型的请求,请求的扩展名为vc,那么配置参数将如下所示:
<httpHandlers>
<add verb="GET" path="*.vc" type="MyHandler.ValidateCodeHandler,MyHandler"/>
</httpHandlers>
在网站应用程序运行的时候,实际得到的配置文件来自于系统能够的machine.config,系统的web.config 和网站自身的web.config合并,系统的配置文件位于一个特殊的文件夹下,在ASP.NET 4.0 下,这个位置可以如下表示:
%systemroot%\Microsoft.NET\Framework\v4.0.30319\Config
在web.config中ASP.NET已经预先配置了57中处理程序的映射,程序员可以通过处理程序接口扩展自定义的处理程序。
使用处理程序生成验证码
1)创建一个类库项目 MyHandler,这个项目的默认命名空间也是 MyHandler
2)类库项目MyHandler中添加一个新类ValidateCodeHandler,实现IHttpHandler接口,为了在处理程序中使用Session状态管理,同时实现IRequiresSessionState接口。
3)在ProcessRequest方法中完成验证码生成的操场。
4)在网站项目中引用类库项目。
5)在网站配置文件web.config中注册这个处理程序。
6)在需要验证码的页面上使用处理程序生产的验证码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace MyHandler
{
class ValidateCodeHandler:System.Web.IHttpHandler,
System.Web.SessionState.IRequiresSessionState
{
private static System.Random random = new Random();
#region IHttpHandler 成员
public bool IsReusable
{
get { throw new NotImplementedException(); }
}
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image.jpeg";
System.Drawing.Image image = new System.Drawing.Bitmap(60, 30);
//生产随机数
int code = random.Next(100, 10000);
string codeString = code.ToString();
//使用会话状态
context.Session["Code"] = codeString;
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(image))
{
g.Clear(System.Drawing.Color.WhiteSmoke);
System.Drawing.StringFormat sf
= new System.Drawing.StringFormat();
sf.Alignment = System.Drawing.StringAlignment.Center;
sf.LineAlignment = System.Drawing.StringAlignment.Center;
g.DrawString(
codeString,
new System.Drawing.Font("Arial",14),
System.Drawing.Brushes.Blue,
new System.Drawing.RectangleF(0,0,
image.Width,image.Height),
sf
);
}
context.Response.ContentType = "image/jpeg";
image.Save(
context.Response.OutputStream,
System.Drawing.Imaging.ImageFormat.Jpeg
);
}
#endregion
}
}