【问题标题】:ASP.NET: Is it possible to call async Task in Global.asax?ASP.NET:是否可以在 Global.asax 中调用异步任务?
【发布时间】:2012-06-21 08:25:40
【问题描述】:

我需要在 Global.asax 中对我的数据库调用一些异步操作。 例如在 Application_AuthenticateRequest 我需要针对 DB 对用户进行身份验证 异步任务可以吗?

【问题讨论】:

标签: asp.net asynchronous task global-asax


【解决方案1】:

现在有一种更简单的方法:

    public MvcApplication()
    {
        var wrapper = new EventHandlerTaskAsyncHelper(DoAsyncWork);
        this.AddOnAuthenticateRequestAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler);
    }

    private async Task DoAsyncWork(object sender, EventArgs e)
    {
        var app = (HttpApplication)sender;
        var ctx = app.Context;

        ...
        await doSomethingAsync();
    }

使用这种方法,您可以使用 async 关键字定义一个方法,并使用“EventHandlerTaskAsyncHelper”类包装该方法,以生成 BeginEventHandler 和 EndEventHandler 方法以传递给 AddOnAuthenticateRequestAsync 调用。

【讨论】:

    【解决方案2】:

    您必须自己添加 AuthenticateRequest 的异步版本。使用以下代码:

    public MvcApplication()
    {
        // Contrary to popular belief, this is called multiple times, one for each 'pipeline' created to handle a request.
        // Wire up the async authenticate request handler.
        AddOnAuthenticateRequestAsync(BeginAuthenticateRequest, EndAuthenticateRequest, null);
    }
    

    接下来的问题是,如何使用 C# 的新 async/await 特性来实现 BeginAuthenticateRequestEndAuthenticateRequest。首先,让我们把异步版本的 AuthenticateRequest 去掉:

    private async Task AuthenticateRequestAsync(object sender, EventArgs args)
    {
        // Yay, let's do async stuff!
        await ...
    }
    

    接下来我们需要做的是提出 BeginAuthenticateRequest 和 EndAuthenticateRequest 的实现。我关注a blog post,但衍生出我自己的实现:

    private IAsyncResult BeginAuthenticateRequest(object sender, EventArgs args, AsyncCallback callback, object state)
    {
        Task task = AuthenticateRequestAsync(sender, args);
        var tcs = new TaskCompletionSource<bool>(state);
    
        task.ContinueWith(_ =>
        {
            if (task.IsFaulted && task.Exception != null) tcs.TrySetException(task.Exception.InnerExceptions);
            else if (task.IsCanceled) tcs.TrySetCanceled();
            else tcs.TrySetResult(true);
    
            if (callback != null) callback(tcs.Task);
        }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default);
    
        return tcs.Task;
    }
    

    您可以阅读整个链接文章以了解其工作原理,但基本上IAsyncResult 是由Task 实现的,因此您只需在完成后调用回调即可。

    最后一点很简单:

    private void EndAuthenticateRequest(IAsyncResult result)
    {
        // Nothing to do here.   
    }
    

    【讨论】:

      【解决方案3】:

      我没有找到使用新的 C# 关键字 async 和 await 的方法,但我们仍然可以使用 APM 模式在 Global.asax 中使用异步操作,因为它实现了 IHttpAsyncHandler 接口。这是一个演示异步的小代码,这里我以WebRequst为例,您的情况请改用数据库操作。

          public Global()
          {
              this.AddOnAuthenticateRequestAsync(BeginGetAsyncData, EndGetAsyncData);
          }
      
          IAsyncResult BeginGetAsyncData(Object src, EventArgs args, AsyncCallback cb, Object state)
          {
              Console.WriteLine("BeginGetAsyncData: thread #" + System.Threading.Thread.CurrentThread.ManagedThreadId);
              WebRequest request = WebRequest.Create("http://www.google.com");
              return request.BeginGetResponse(cb, request); // call database async operation like SqlCommand.BeginExecuteReader()
          }
      
          void EndGetAsyncData(IAsyncResult ar)
          {
              Console.WriteLine("EndGetAsyncData: thread #" + System.Threading.Thread.CurrentThread.ManagedThreadId);
      
              WebRequest requst = (WebRequest)ar.AsyncState;
              System.Net.WebResponse response = requst.EndGetResponse(ar); // call database async operation like SqlCommand.EndExecuteReader()
      
              Console.WriteLine(new StreamReader(response.GetResponseStream()).ReadToEnd());
              response.Close();
          }
      
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-29
      • 1970-01-01
      • 1970-01-01
      • 2016-04-24
      • 1970-01-01
      • 2016-01-02
      • 2017-09-17
      相关资源
      最近更新 更多