我们接下来介绍的HttpModule就是通过HttpApplication事件注册的机制实现相应的功能的。表1按照实现的先后顺利列出了HttpApplication在处理每一个请求时触发的事件名称。
表1 名称
描述
BeginRequest
HTTP管道开始处理请求时,会触发BeginRequest事件
AuthenticateRequest,PostAuthenticateRequest
ASP.NET先后触发这两个事件,使安全模块对请求进行身份验证
AuthorizeRequest,PostAuthorizeRequest
ASP.NET先后触发这两个事件,使安全模块对请求进程授权
ResolveRequestCache,PostResolveRequestCache
ASP.NET先后触发这两个事件,以使缓存模块利用缓存的直接对请求直接进程响应(缓存模块可以将响应内容进程缓存,对于后续的请求,直接将缓存的内容返回,从而提高响应能力)。
PostMapRequestHandler
对于访问不同的资源类型,ASP.NET具有不同的HttpHandler对其进程处理。对于每个请求,ASP.NET会通过扩展名选择匹配相应的HttpHandler类型,成功匹配后,该实现被触发
AcquireRequestState,PostAcquireRequestState
ASP.NET先后触发这两个事件,使状态管理模块获取基于当前请求相应的状态,比如SessionState
PreRequestHandlerExecute,PostRequestHandlerExecute
ASP.NET最终通过一请求资源类型相对应的HttpHandler实现对请求的处理,在实行HttpHandler前后,这两个实现被先后触发
ReleaseRequestState,PostReleaseRequestState
ASP.NET先后触发这两个事件,使状态管理模块释放基于当前请求相应的状态
UpdateRequestCache,PostUpdateRequestCache
ASP.NET先后触发这两个事件,以使缓存模块将HttpHandler处理请求得到的相应保存到输出缓存中
LogRequest,PostLogRequest
ASP.NET先后触发这两个事件为当前请求进程日志记录
EndRequest
整个请求处理完成后,EndRequest事件被触发
对于一个ASP.NET应用来说,HttpApplication派生于global.asax文件,我们可以通过创建global.asax文件对HttpApplication的请求处理行为进行定制。global.asax采用一种很直接的方式实现了这样的功能,这种方式既不是我们常用的方法重写(Method Overriding)或者事件注册,而是直接采用方法名匹配。在global.asax中,我们按照这样的方法命名规则进行事件注册:Application_{Event Name}。比如Application_BeginRequest方法用于处理HttpApplication的BeginRequest事件。如果通过VS创建一个global.asax文件,下面是默认的定义。
<%@ Application Language="C#" %><script runat="server">void Application_Start(object sender, EventArgs e) {}void Application_End(object sender, EventArgs e) {}void Application_Error(object sender, EventArgs e) {}void Session_Start(object sender, EventArgs e) {}void Session_End(object sender, EventArgs e) {}</script>HttpModule
ASP.NET为创建各种.NET Web应用提供了强大的平台,它拥有一个具有高度可扩展性的引擎,并且能够处理对于不同资源类型的请求。那么,是什么成就了ASP.NET的高可扩展性呢? HttpModule功不可没。
从功能上讲,HttpModule之于ASP.NET,就好比ISAPI Filter之于IIS一样。IIS将接收到的请求分发给相应的ISAPI Extension之前,注册的ISAPI Filter会先截获该请求。ISAPI Filter可以获取甚至修改请求的内容,完成一些额外的功能。与之相似地,当请求转入ASP.NET管道后,最终负责处理该请求的是与请求资源类型相匹配的HttpHandler对象,但是在Handler正式工作之前,ASP.NET会先加载并初始化所有配置的HttpModule对象。HttpModule在初始化的过程中,会将一些功能注册到HttpApplication相应的事件中,那么在HttpApplication整个请求处理生命周期中的某个阶段,相应的事件会被触发,通过HttpModule注册的事件处理程序也得以执行。
所有的HttpModule都实现了IHttpModule接口,下面是IHttpModule的定义。其中Init方法用于实现HttpModule自身的初始化,该方法接受一个HttpApplication对象,有了这个对象,事件注册就很容易了。
public interface IHttpModule{void Dispose();void Init(HttpApplication context);}ASP.NET提供的很多基础构件(Infrastructure)功能都是通过相应的HttpModule实现的,下面类列出了一些典型的HttpModule:
OutputCacheModule:实现了输出缓存(Output Caching)的功能; SessionStateModule:在无状态的HTTP协议上实现了基于会话(Session)的状态; WindowsAuthenticationModule + FormsAuthenticationModule + PassportAuthentication- Module:实现了3种典型的身份认证方式:Windows认证、Forms认证和Passport认证; UrlAuthorizationModule + FileAuthorizationModule:实现了基于Uri和文件ACL(Access Control List)的授权。 而另外一个重要的HttpModule与WCF相关,那么就是System.ServiceModel. Activation.HttpModule。HttpModule定义在System.ServiceModel程序集中,在默认的情况下,HttpModule完成了基于IIS的寄宿工作。
除了这些系统定义的HttpModule之外,我们还可以自定义HttpMoudle。通过Web.config,我们可以很容易地将其注册到我们的Web应用中。
HttpHandler
如果说HttpModule相当于IIS的ISAPI Filter的话,我们可以说HttpHandler则相当于IIS的ISAPI Extension,HttpHandler在ASP.NET中扮演请求的最终处理者的角色。对于不同资源类型的请求,ASP.NET会加载不同的Handler来处理,也就是说.aspx page与.asmx web service对应的Handler是不同的。
所有的HttpHandler都实现了接口IHttpHandler。下面是IHttpHandler的定义,方法ProcessRequest提供了处理请求的实现。
public interface IHttpHandler{void ProcessRequest(HttpContext context);bool IsReusable { get; }}对于某些HttpHandler,具有一个与之相关的HttpHandlerFactory,用于创建或者获取相应的HttpHandler。HttpHandlerFactory实现接口IHttpHandlerFactory,方法GetHandler用于创建新的HttpHandler,或者获取已经存在的HttpHandler。
public interface IHttpHandlerFactory{IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);void ReleaseHandler(IHttpHandler handler);}HttpHandler和HttpHandlerFactory的类型都可以通过相同的方式配置到Web.config中。下面一段配置包含对3种典型的资源类型的HttpHandler配置:.aspx,.asmx和.svc。可以看到基于WCF Service的HttpHandler类型为:System.ServiceModel.Activation.HttpHandler。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<httpHandlers>
<add path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>
<add path="*.asmx" verb="*" type="System.Web.Services.Protocols.WebServiceHandlerFactory, System.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" validate="False"/>
</httpHandlers>
</system.web>
</configuration>

