• ASP.NET中异步HttpModule的实现方式
  • 王帆 发表于 2015/12/29 13:46:00 | 分类标签: 异步编程 HttpModule
  • 我们再编写一个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 =
            @"server=localhost\sqlexpress;Integrated Security=SSPI;Asynchronous Processing=true";
    
    
        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。

  • 请您注意

    ·自觉遵守:爱国、守法、自律、真实、文明的原则

    ·尊重网上道德,遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他各项有关法律法规

    ·严禁发表危害国家安全,破坏民族团结、国家宗教政策和社会稳定,含侮辱、诽谤、教唆、淫秽等内容的作品

    ·承担一切因您的行为而直接或间接导致的民事或刑事法律责任

    ·您在编程中国社区新闻评论发表的作品,本网站有权在网站内保留、转载、引用或者删除

    ·参与本评论即表明您已经阅读并接受上述条款

  • 感谢本文作者
  • 作者头像
  • 昵称:王帆
  • 加入时间:2013/6/13 0:00:00
  • TA的签名
  • 这家伙很懒,虾米都没写
  • +进入TA的空间
  • 以下内容也很赞哦
分享按钮