15

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

4

3 回答 3

31

现在有一种更简单的方法可以做到这一点:

    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 调用。

于 2014-03-15T14:02:21.847 回答
2

我没有找到使用新 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();
    }
于 2012-06-20T02:24:12.973 回答
1

您必须自己添加 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);
}

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

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

我们接下来需要做的是提出 BeginAuthenticateRequest 和 EndAuthenticateRequest 的实现。我关注了一篇博客文章,但得出了我自己的实现:

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.   
}
于 2013-08-23T08:19:40.480 回答