名称 | 说明 |
---|---|
Dispose | Disposes of the resources (other than memory) used by the module that implements IHttpModule. |
Init | Initializes a module and prepares it to handle requests. |
IHttpModule接口只有两个方法。
void Init(HttpApplication app);
void Dispose();
Init方法接受一个服务该请求的HttpApplication对象的引用。使用该引用可以连接到系统事件。HttpApplication对象也有一个称为Context的对象,该对象提供对ASP.NET应用程序的内在属性的引用。这样,我们就可以访问Response, Request, Session等。
表2.5列出了HTTP模块监听和处理的事件。
表2.5 HttpApplication事件
事 件 | 描 述 |
AcquireRequestState, PostAcquireRequestState | 当实际服务请求的处理程序获得与该请求关联的状态信息时发生。ASP.NET 1.x不支持PostAcquireRequestState事件 |
AuthenticateRequest, PostAuthenticateRequest | 当一个安全模块已经建立用户的身份时发生。ASP.NET 1.x不支持PostAuthenticateRequest事件 |
AuthorizeRequest, PostAuthorizeRequest | 当一个安全模块已经验证用户授权时发生。ASP.NET 1.x不支持PostAuthorizeRequest事件 |
BeginRequest | HTTP管道一开始处理请求就发出该事件 |
Disposed | 由于调用了Dispose,HttpApplication对象被处置时发出该事件。 |
EndRequest | 作为HTTP管道执行链的最后一个事件发出 |
Error | 抛出一个未处理的异常时发生 |
PostMapRequestHandler | 当服务请求的HTTP处理程序被找到时发出。ASP.NET 1.x不支持该事件 |
PostRequestHandlerExecute | 当所选的HTTP处理程序完成执行时发出该事件。这时已经生成响应文本 |
PreRequestHandlerExecute | 正好在所选的HTTP处理程序开始工作前发出该事件 |
PreSendRequestContent | 正好在ASP.NET运行库把响应文本发送给客户之前发出该事件 |
PreSendRequestHeaders | 正好在ASP.NET运行库把HTTP头发送给客户之前发出该事件 |
ReleaseRequestState, PostReleaseRequestState | 当处理程序释放与当前请求关联的状态信息时发生。ASP.NET 1.x不支持PostReleaseRequestState事件 |
ResolveRequestCache, PostResolveRequestCache | 当ASP.NET运行库通过输出缓存解决该请求时发生。ASP.NET 1.x不支持PostResolveRequestCache事件 |
UpdateRequestCache, PostUpdateRequestCache | 当ASP.NET运行库将当前请求的响应存储在输出缓存(用来服务随后的请求)中时发生。ASP.NET 1.x不支持PostUpdateRequestCache事件 |
所有这些事件由HttpApplication对象提供的,而HTTP模块作为Init方法的一个参数接受该对象。
下面来实现这个接口:
public class MarkerModule : IHttpModule
{
public void Init(HttpApplication app)
{
// Register for pipeline events
}
public void Dispose()
{
// Nothing to do here
}
}
HttpApplication类调用Init方法来装载该模块。在Init方法中,通常只需注册自己的事件处理程序。Dispose方法多半是空的。HTTP模块的核心实际上就是自定义的事件处理程序。
1. 绑定事件
Marker示例模块注册两个管道事件,它们是BeginRequest和EndRequest。BeginRequest是开始处理请求时第一个命中HTTP应用程序对象的事件;EndRequest是表明即将处理完请求,这是实施干预的最后机会的事件。通过处理这两个事件,可以在常规的HTTP处理程序(派生于Page的类)之前和之后,将自定义的文本写入输出流中。
如下清单展示了示例模块的Init和Dispose方法的过程实现:
public void Init(HttpApplication app)
{
// Register for pipeline events
app.BeginRequest += new EventHandler(OnBeginRequest);
app.EndRequest += new EventHandler(OnEndRequest);
}
public void Dispose()
{
}
BeginRequest和EndRequest事件处理程序结构类似。它们从发送方获得对当前HttpApplication对象的引用,并从该引用那里获得HTTP上下文。接着,它们使用Reponse对象追加文本或自定义标题。
public void OnBeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication) sender;
HttpContext ctx = app.Context;
// More code here
// PageHeaderText is a constant string defined elsewhere
ctx.Response.AppendHeader("Author", "DinoE");
ctx.Response.Write(PageHeaderText);
}
public void OnEndRequest(object sender, EventArgs e)
{
// Get access to the HTTP context
HttpApplication app = (HttpApplication) sender;
HttpContext ctx = app.Context;
// More code here
// Append some custom text
// PageFooterText is a constant string defined elsewhere
ctx.Response.Write(PageFooterText);
}
OnBeginRequest写入标准的页面标题文本并添加一个自定义的HTTP头。OnEndRequest只是追加页面的页脚。该HTTP模块的效果如图2.7所示。
图2.7 Marker HTTP模块将一个标题和页脚添加到应用程序内的每个页面
注意 图中的工具,即IEWatch 2.0,是Microsoft Internet Explorer的一个插件程序,该工具可以分析HTTP/HTTPS请求和HTML源代码。我们可以从http://www.iewatch.com获取它。
Internet Explorer底部的可停靠窗口,展示了浏览器正在发送和接收的所有HTTP头。显然,响应文本中的自定义的标题是可见的。
2. 用配置文件注册该模块
通过向配置文件的<httpModules>节添加一个配置项,可以注册一个新的HTTP模块。<httpModules>配置节的语法类似于HTTP处理程序的语法。使用<add>节点,并规定name和type属性可以添加一个新的模块。name属性包含该模块的公开名称。该名称将被用来选择HttpApplication的Modules集合中的模块。如果该模块激发自定义事件,则该名称还可以在global.asax文件中用作构建自动的事件处理程序的前缀。
<system.web>
<httpModules>
<add name="Marker"
type="ProAspNet20.CS.Components.MarkerModule,ProAspCompLib" />
</httpModules>
</system.web>
type属性使用常见的逗号隔离字符串,它可设置类及其相关程序集的名称。这些配置设置既可以存储在应用程序配置文件中,也可以存储在机器配置文件中。在前一种情况中,只有应用程序的页面受影响;而在后一种情况下,所有应用程序中的所有页面都将由指定的模块进行处理。
这些模块的应用顺序取决于其在配置列表中的物理顺序。可以删掉一个系统模块,并用我们自己的具有类似功能的模块替换它。在这种情况下,在应用程序的web.config文件中,使用<remove>节点删去默认模块,然后使用<add>插入自己的模块。如果需要完全重新定义HTTP模块的应用顺序,可以使用<clear>节点清除所有的默认模块,然后按自己喜欢的顺序重新注册它们。
3. 访问其他HTTP模块
刚刚讨论的示例说明了如何绑定管道事件——即,HttpApplication对象激发的事件。但是其他模块激发的事件是什么呢?HttpApplication对象提供了一个名为Modules的属性,它获得当前应用程序模块的集合。
Modules属性的类型为HttpModuleCollection,其中包括应用程序模块的名称。该集合类继承自NameObjectCollectionBase抽象类,这是一个由字符串和对象组成的组合对的集合。字符串指示模块的公开名称,对象是该模块的真实实例。要访问处理会话状态的模块,需要如下编码:
SessionStateModule sess = app.Modules["Session"];
sess.Start += new EventHandler(OnSessionStart);
如前所述,还可以在global.asax文件中处理HTTP模块引起的事件,并使用ModuleName_EventName规则来命名事件处理程序。模块名称只是在注册一个HTTP模块时需要定义的设置之一。