异步HttpModule的实现方式

📅 2026/7/5 4:45:10
异步HttpModule的实现方式
在【用Asp.net写自己的服务框架】中 我示范过如果编写一个HttpModule通常只要我们实现IHttpModule接口并在Init方法中订阅一些事件就可以了internal class DirectProcessRequestMoudle : IHttpModule { public void Init(HttpApplication app) { app.PostAuthorizeRequest new EventHandler(app_PostAuthorizeRequest); }HttpHandler有异步接口的IHttpAsyncHandler但HttpModule却只有一个接口IHttpModule不管是同步还是异步。 异步HttpModule的实现方式并不是订阅HttpApplication的事件而是调用HttpApplication的一些注册异步操作的方法来实现的还是在Init事件中 这些方法可参考以下列表// 将指定的 System.Web.HttpApplication.AcquireRequestState 事件 // 添加到当前请求的异步 System.Web.HttpApplication.AcquireRequestState事件处理程序的集合。 public void AddOnAcquireRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.AuthenticateRequest 事件 // 添加到当前请求的异步 System.Web.HttpApplication.AuthenticateRequest事件处理程序的集合。 public void AddOnAuthenticateRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.AuthorizeRequest 事件 // 添加到当前请求的异步 System.Web.HttpApplication.AuthorizeRequest事件处理程序的集合。 public void AddOnAuthorizeRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.BeginRequest 事件 // 添加到当前请求的异步 System.Web.HttpApplication.BeginRequest事件处理程序的集合。 public void AddOnBeginRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.EndRequest 事件 // 添加到当前请求的异步 System.Web.HttpApplication.EndRequest事件处理程序的集合。 public void AddOnEndRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); public void AddOnLogRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); public void AddOnMapRequestHandlerAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.PostAcquireRequestState 事件 // 添加到当前请求的异步 System.Web.HttpApplication.PostAcquireRequestState事件处理程序的集合。 public void AddOnPostAcquireRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.PostAuthenticateRequest 事件 // 添加到当前请求的异步 System.Web.HttpApplication.PostAuthenticateRequest事件处理程序的集合。 public void AddOnPostAuthenticateRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.PostAuthorizeRequest 事件 // 添加到当前请求的异步 System.Web.HttpApplication.PostAuthorizeRequest事件处理程序的集合。 public void AddOnPostAuthorizeRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); public void AddOnPostLogRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.PostMapRequestHandler 事件 // 添加到当前请求的异步 System.Web.HttpApplication.PostMapRequestHandler事件处理程序的集合。 public void AddOnPostMapRequestHandlerAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.PostReleaseRequestState 事件 // 添加到当前请求的异步 System.Web.HttpApplication.PostReleaseRequestState事件处理程序的集合。 public void AddOnPostReleaseRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.PostRequestHandlerExecute 事件 // 添加到当前请求的异步 System.Web.HttpApplication.PostRequestHandlerExecute事件处理程序的集合。 public void AddOnPostRequestHandlerExecuteAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.PostResolveRequestCache 事件 // 添加到当前请求的异步 System.Web.HttpApplication.PostResolveRequestCache事件处理程序的集合。 public void AddOnPostResolveRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.PostUpdateRequestCache 事件 // 添加到当前请求的异步 System.Web.HttpApplication.PostUpdateRequestCache事件处理程序的集合。 public void AddOnPostUpdateRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.PreRequestHandlerExecute 事件 // 添加到当前请求的异步 System.Web.HttpApplication.PreRequestHandlerExecute事件处理程序的集合。 public void AddOnPreRequestHandlerExecuteAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.ReleaseRequestState 事件 // 添加到当前请求的异步 System.Web.HttpApplication.ReleaseRequestState事件处理程序的集合。 public void AddOnReleaseRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.ResolveRequestCache 事件处理程序 // 添加到当前请求的异步 System.Web.HttpApplication.ResolveRequestCache事件处理程序的集合。 public void AddOnResolveRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state); // 将指定的 System.Web.HttpApplication.UpdateRequestCache 事件 // 添加到当前请求的异步 System.Web.HttpApplication.UpdateRequestCache事件处理程序的集合。 public void AddOnUpdateRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state);每个方法的含义从它们的名字是可以看出。 异步HttpModule的实现方式需要将异步对应的Begin/End二个方法分别做为委托参数传入这些方法中。注意这些方法的签名与Page.AddOnPreRenderCompleteAsync()是一致的因此它们的具体用法也与Page.AddOnPreRenderCompleteAsync()一样。为什么这里不设计成订阅事件的方式我想是因为如果采用事件模式调用者可以只订阅其中的一个事件ASP.NET不容易控制还有object state这个参数不便于在订阅事件时传入。异步HttpModule的示例代码如下/// summary /// 【示例代码】演示异步的HttpModule /// 说明这个示例一丁点意义也没有纯粹是为了演示。 /// /summary public class MyAsyncHttpModule : IHttpModule { public static readonly object HttpContextItemsKey new object(); private static readonly string s_QueryDatabaseListScript select dtb.name from master.sys.databases as dtb order by 1; private static readonly string s_ConnectionString serverlocalhost\sqlexpress;Integrated SecuritySSPI;Asynchronous Processingtrue; public void Init(HttpApplication app) { // 注册异步事件 app.AddOnBeginRequestAsync(BeginCall, EndExecuteReader, null); } private IAsyncResult BeginCall(object sender, EventArgs e, AsyncCallback cb, object extraData) { SqlConnection connection new SqlConnection(s_ConnectionString); connection.Open(); SqlCommand command new SqlCommand(s_QueryDatabaseListScript, connection); CallbackParam cbParam new CallbackParam { Command command, Context HttpContext.Current }; return command.BeginExecuteReader(cb, cbParam); } private class CallbackParam { public SqlCommand Command; public HttpContext Context; } private void EndExecuteReader(IAsyncResult ar) { CallbackParam cbParam (CallbackParam)ar.AsyncState; StringBuilder sb new StringBuilder(); try { using( SqlDataReader reader cbParam.Command.EndExecuteReader(ar) ) { while( reader.Read() ) { sb.Append(reader.GetString(0)).Append(; ); } } } catch( Exception ex ) { cbParam.Context.Items[HttpContextItemsKey] ex.Message; } finally { cbParam.Command.Connection.Close(); } if( sb.Length 0 ) cbParam.Context.Items[HttpContextItemsKey] 数据库列表 sb.ToString(0, sb.Length - 2); } public void Dispose() { } }页面可以使用如下方式获得MyAsyncHttpModule的结果public partial class TestMyAsyncHttpModule : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string result (string)HttpContext.Current.Items[MyAsyncHttpModule.HttpContextItemsKey] ?? 没有开启MyAsyncHttpModule请在web.config中启用它。; Response.Write(result); } }说明管线处理过程中可能有多个HttpModule但是异步的HttpModule在执行时只是在一个阶段内所有的HttpModule采用异步方式工作。 当进入下一个阶段前必须要等到所有HttpModule全部在当前阶段内执行完毕。通常情况下是没有必要写异步的HttpModule的。这是我写的第一个异步HttpModule。回到顶部异步的 Web Service由于Web Service也是受ASP.NET支持且随着ASP.NET一起出现。我们再来看一下如果将一个同步的服务方法改变成异步的方法。注意将方法由同步改成异步版本是不影响客户端的。以下代码是一个同步版本的服务方法[WebMethod] public string ExtractNumber(string str) { //return ........ }再来看一下最终的异步实现版本[WebMethod] public IAsyncResult BeginExtractNumber(string str, AsyncCallback cb, object state) { MyHttpClientstring, string http new MyHttpClientstring, string(); http.UserData Begin ThreadId: Thread.CurrentThread.ManagedThreadId.ToString(); return http.BeginSendHttpRequest(ServiceUrl, str, cb, http); } [WebMethod] public string EndExtractNumber(IAsyncResult ar) { MyHttpClientstring, string http (MyHttpClientstring, string)ar.AsyncState; try{ return http.EndSendHttpRequest(ar) , http.UserData.ToString() , End ThreadId: Thread.CurrentThread.ManagedThreadId.ToString(); } catch(Exception ex){ return ex.ToString(); } }其实要做的修改与IHttpHandler到IHttpAsyncHandler的工作差不多在原有的同步方法后面加二个与异步操作有关的参数 并且返回值改为IAsyncResult然后再添加一个EndXxxx方法就可以了当然了EndXxxx方法的传入