在之前的ASP.NET是如何在IIS下工作的这篇文章中介绍了ASP.NET与IIS配合工作的机制,在http请求经过一系列处理后,最后到达ASP.NET管道中,这时,就是Http Modules和HttpHandler出场的时候了。
再来摆出管道工作时序图来一看:
HttpModule
HttpModule是类似于过滤器的作用,可以没有,也可以有任意个,每一个都可以订阅管道事件中的任意个事件,在每个订阅的事件中可自定义功能实现。
HttpModule是实现IHttpModule接口的类。接口如下:
public interface IHttpModule { // 摘要: // 处置由实现 System.Web.IHttpModule 的模块使用的资源(内存除外)。 void dispose(); // // 摘要: // 初始化模块,并使其为处理请求做好准备。 // // 参数: // context: // 一个 System.Web.HttpApplication,它提供对 ASP.NET 应用程序内所有应用程序对象的公用的方法、属性和事件的访问 void Init(HttpApplication context); }
下面实现一个HttpModule,并订阅管道中的一系列事件,订阅事件就是在Init方法中绑定EventHandler的过程:
代码有点长,因为我把每一个事件都订阅了,这样一来可以清楚的看出哪些事件执行了,这些事件执行的先后顺序是什么。代码如下:
public class MyModule : IHttpModule { #region IHttpModule Members public void dispose() { //此处放置清除代码。 } public void Init(HttpApplication context) { // 下面是如何处理 LogRequest 事件并为其 // 提供自定义日志记录实现的示例 context.LogRequest += new EventHandler(OnLogRequest); context.BeginRequest += new EventHandler(context_BeginRequest); context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest); context.AcquireRequestState += new EventHandler(context_AcquireRequestState); context.AuthorizeRequest += new EventHandler(context_AuthorizeRequest); context.disposed += new EventHandler(context_disposed); context.Error += new EventHandler(context_Error); context.EndRequest += new EventHandler(context_EndRequest); context.MapRequestHandler += new EventHandler(context_MapRequestHandler); context.PostAcquireRequestState += new EventHandler(context_PostAcquireRequestState); context.PostAuthenticateRequest += new EventHandler(context_PostAuthenticateRequest); context.PostAuthorizeRequest += new EventHandler(context_PostAuthorizeRequest); context.PostLogRequest += new EventHandler(context_PostLogRequest); context.PostReleaseRequestState += new EventHandler(context_PostReleaseRequestState); context.PostRequestHandlerExecute += new EventHandler(context_PostRequestHandlerExecute); context.PostResolveRequestCache += new EventHandler(context_PostResolveRequestCache); context.PostUpdateRequestCache += new EventHandler(context_PostUpdateRequestCache); context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState); context.RequestCompleted += new EventHandler(context_RequestCompleted); context.ResolveRequestCache += new EventHandler(context_ResolveRequestCache); context.UpdateRequestCache += new EventHandler(context_UpdateRequestCache); context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute); context.PreSendRequestContent += new EventHandler(context_PreSendRequestContent); context.PreSendRequestHeaders += new EventHandler(context_PreSendRequestHeaders); context.PostMapRequestHandler += new EventHandler(context_PostMapRequestHandler); } void context_Error(object sender, EventArgs e) { WriteLog("Error"); //HttpContext.Current.Response.Write("Error<br />"); } void context_UpdateRequestCache(object sender, EventArgs e) { WriteLog("UpdateRequestCache"); //HttpContext.Current.Response.Write("UpdateRequestCache<br />"); } void context_ResolveRequestCache(object sender, EventArgs e) { WriteLog("ResolveRequestCache"); // HttpContext.Current.Response.Write("ResolveRequestCache<br />"); } void context_RequestCompleted(object sender, EventArgs e) { WriteLog("RequestCompleted"); // HttpContext.Current.Response.Write("RequestCompleted<br />"); } void context_ReleaseRequestState(object sender, EventArgs e) { WriteLog("ReleaseRequestState"); //HttpContext.Current.Response.Write("ReleaseRequestState<br />"); } void context_PostUpdateRequestCache(object sender, EventArgs e) { WriteLog("PostUpdateRequestCache"); //HttpContext.Current.Response.Write("PostUpdateRequestCache<br />"); } void context_PostResolveRequestCache(object sender, EventArgs e) { WriteLog("PostResolveRequestCache"); //HttpContext.Current.Response.Write("PostResolveRequestCache<br />"); } void context_PostRequestHandlerExecute(object sender, EventArgs e) { WriteLog("PostRequestHandlerExecute"); //HttpContext.Current.Response.Write("PostRequestHandlerExecute<br />"); } void context_PostReleaseRequestState(object sender, EventArgs e) { WriteLog("PostReleaseRequestState"); //HttpContext.Current.Response.Write("PostReleaseRequestState<br />"); } void context_PostLogRequest(object sender, EventArgs e) { WriteLog("PostLogRequest"); //HttpContext.Current.Response.Write("PostLogRequest<br />"); } void context_PostAuthorizeRequest(object sender, EventArgs e) { WriteLog("PostAuthorizeRequest"); //HttpContext.Current.Response.Write("PostAuthorizeRequest<br />"); } void context_PostAuthenticateRequest(object sender, EventArgs e) { WriteLog("PostAuthenticateRequest"); //HttpContext.Current.Response.Write("PostAuthenticateRequest<br />"); } void context_PostAcquireRequestState(object sender, EventArgs e) { WriteLog("PostAcquireRequestState"); //HttpContext.Current.Response.Write("PostAcquireRequestState<br />"); } void context_MapRequestHandler(object sender, EventArgs e) { WriteLog("MapRequestHandler"); //HttpContext.Current.Response.Write("MapRequestHandler<br />"); } void context_disposed(object sender, EventArgs e) { WriteLog("disposed"); //HttpContext.Current.Response.Write("disposed<br />"); } void context_AuthorizeRequest(object sender, EventArgs e) { WriteLog("AuthorizeRequest"); //HttpContext.Current.Response.Write("AuthorizeRequest<br />"); } void context_AcquireRequestState(object sender, EventArgs e) { WriteLog("AcquireRequestState"); //HttpContext.Current.Response.Write("AcquireRequestState<br />"); } void context_PreSendRequestHeaders(object sender, EventArgs e) { WriteLog("PreSendRequestHeaders"); //HttpContext.Current.Response.Write("PreSendRequestHeaders<br />"); } void context_PreSendRequestContent(object sender, EventArgs e) { WriteLog("PreSendRequestContent"); //HttpContext.Current.Response.Write("PreSendRequestContent<br />"); } void context_PreRequestHandlerExecute(object sender, EventArgs e) { WriteLog("PreRequestHandlerExecute"); //HttpContext.Current.Response.Write("PreRequestHandlerExecute<br />"); } void context_EndRequest(object sender, EventArgs e) { WriteLog("EndRequest"); //HttpContext.Current.Response.Write("EndRequest<br />"); } void context_BeginRequest(object sender, EventArgs e) { WriteLog("*******************************************************************************"); HttpApplication app = sender as HttpApplication; WriteLog(app.Context.Request.Path); WriteLog("BeginRequest"); //HttpContext.Current.Response.Write("BeginRequest<br />"); } void context_AuthenticateRequest(object sender, EventArgs e) { WriteLog("AuthenticateRequest"); //HttpContext.Current.Response.Write("AuthenticateRequest<br />"); } #endregion public void OnLogRequest(Object source, EventArgs e) { //可以在此处放置自定义日志记录逻辑 WriteLog("OnLogRequest"); //HttpContext.Current.Response.Write("OnLogRequest<br />"); } public void context_PostMapRequestHandler(object sender, EventArgs e) { WriteLog("PostMapRequestHandler"); //HttpContext.Current.Response.Write("PostMapRequestHandler<br />"); } public void WriteLog(string message) { string path = @"d:\aspnet\httpmodule.txt"; StreamWriter writer = null; if (!File.Exists(path)) { writer = File.CreateText(path); } else { FileInfo info = new FileInfo(path); writer = info.AppendText(); } writer.WriteLine(message); writer.Flush(); writer.Close(); } }
订阅的事件实现中,将事件名称保存到我本地D盘的一个文本文件中。
代码实现完毕了,下一步就是要代码起作用了,很简单,只需要在web.config中简单配置就可以了。配置中注意IIS7集成模式和IIS7经典模式(包括IIS6)的区别,配置如下:
<!--IIS6或者IIS7经典模式--> <system.web> <httpModules> <add name="mycustommodule" type="fengzheng.MyModule,handler_modules"/> </httpModules> </system.web> <!--IIS7集成模式--> <system.webServer> <modules> <add name="mycustommodule" type="fengzheng.MyModule,handler_modules"/> </modules> </system.webServer>
如此一来,一个HttpModule及其配置工作就完成了,接下来,发布网站到IIS或者直接在VS中运行,随便访问项目中的一个文件(任何文件类型都可以),我的项目中有一个WebForm2.aspx的页面,我在浏览器中访问这个页面,发现页面是空白的,因为页面中我什么都没写,上面的Module实现中,我把输出全部放到本地D盘的一个文本文件中了,ok,打开那个文本文件。如图:
我们看到输出内容,第2行是访问的页面地址,下面依次为订阅的事件输出,我们清楚的看到了事件的执行顺序。
@H_404_72@BeginRequest #发出信号表示创建任何给定的新请求。 此事件始终被引发,并且始终是请求处理期间发生的第一个事件 AuthenticateRequest #发出信号表示配置的身份验证机制已对当前请求进行了身份验证。 订阅 AuthenticateRequest 事件可确保在处理附加模块或事件处理程序之前对请求进行身份验证 PostAuthenticateRequest #预订 PostAuthenticateRequest 事件的功能可以访问由 PostAuthenticateRequest 处理的任何数据 AuthorizeRequest #发出信号表示 ASP.NET 已对当前请求进行了授权。 订阅 AuthorizeRequest 事件可确保在处理附加的模块或事件处理程序之前对请求进行身份验证和授权 PostAuthorizeRequest #发出信号表示 ASP.NET 已对当前请求进行了授权。 订阅 PostAuthorizeRequest 事件可确保在处理附加的模块或处理程序之前对请求进行身份验证和授权 ResolveRequestCache #引发这个事件来决定是否可以使用从输出缓冲返回的内容来结束请求。这依赖于Web应用程序的输出缓冲时怎样设置的 PostResolveRequestCache #在 ASP.NET 跳过当前事件处理程序的执行并允许缓存模块满足来自缓存的请求时发生 MapRequestHandler #ASP.NET 基础结构使用 MapRequestHandler 事件来确定用于当前请求的请求处理程序 PostMapRequestHandler #在 ASP.NET 已将当前请求映射到相应的事件处理程序时发生 AcquireRequestState #当 ASP.NET 获取与当前请求关联的当前状态(如会话状态)时发生 PostAcquireRequestState #预订 AcquireRequestState 事件的功能可以访问由 PostAcquireRequestState 处理的任何数据 PreRequestHandlerExecute #在ASP.NET开始执行HTTP请求的处理程序之前引发这个事件。在这个事件之后,ASP.NET 把该请求转发给适当的HTTP处理程序 PostRequestHandlerExecute #在 ASP.NET 事件处理程序(例如,某页或某个 XML Web service)执行完毕时发生 ReleaseRequestState #在 ASP.NET 执行完所有请求事件处理程序后发生。 该事件将使状态模块保存当前状态数据 PostReleaseRequestState #在 ASP.NET 已完成所有请求事件处理程序的执行并且请求状态数据已存储时发生 UpdateRequestCache #当 ASP.NET 执行完事件处理程序以使缓存模块存储将用于从缓存为后续请求提供服务的响应时发生 PostUpdateRequestCache #在 ASP.NET 完成缓存模块的更新并存储了用于从缓存中为后续请求提供服务的响应后,发生此事件 OnLogRequest #恰好在 ASP.NET 为当前请求执行任何记录之前发生,即使发生错误,也会引发 LogRequest 事件 PostLogRequest #在 ASP.NET 处理完 LogRequest 事件的所有事件处理程序后发生 EndRequest #在 ASP.NET 响应请求时作为 HTTP 执行管线链中的最后一个事件发生 PreSendRequestContent #恰好在 ASP.NET 向客户端发送内容之前发生,可能发生多次 PreSendRequestHeaders #恰好在 ASP.NET 向客户端发送 HTTP 标头之前发生 RequestCompleted #在任何托管模块和处理程序执行后,它使模块清理资源