ASP.NET: Можно ли вызвать async Task в Global.asax?

Мне нужно вызвать некоторые операции async в моей БД в Global.asax. например, в Application_AuthenticateRequest Мне нужно проверить подлинность пользователя с помощью DB Возможно ли это с помощью асинхронных задач?

Ответ 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

Я не нашел способ использовать новое ключевое слово С# async и ждать, но мы все еще можем использовать шаблон APM для использования асинхронных операций в Global.asax, поскольку он реализовал интерфейс IHttpAsyncHandler. Вот небольшой код для демонстрации async, здесь я использую пример 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();
    }

Ответ 3

Вы должны добавить асинхронную версию 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);
}

Проблема заключается в том, как реализовать BeginAuthenticateRequest и EndAuthenticateRequest, используя новые функции async/await С#. Во-первых, позвольте получить нашу асинхронную версию AuthenticateRequest:

private async Task AuthenticateRequestAsync(object sender, EventArgs args)
{
    // Yay, let 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.   
}