Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET: Is it possible to call async Task in Global.asax?

I need to call some async operations on my DB in Global.asax. for example in Application_AuthenticateRequest I need to Authenticate user against DB Is it possible with async Tasks?

like image 673
user1328761 Avatar asked Jun 19 '12 09:06

user1328761


People also ask

How do you call async Task Actionresult?

1 Answer. Show activity on this post. It is best for you to use async/await down the whole call stack which is possible with MVC. Mark your Action as async and then use the await keyword to wait for the results from the CsvReader method.

How do you call async method in page load?

How can I call a async method on Page_Load ? If you change the method to static async Task instead of void, you can call it by using SendTweetWithSinglePicture("test", "path"). Wait() . Avoid async void unless you are using it for events.

How do you call async method in controller?

STEP 01 Create new MVC Application project, named as "Async". In the File menu, click New Project. In the "New Project" dialog box, under Project types, expand Visual C#, and then click "Web". In the Name box, type "Async", then click on Ok.

What happens when you call async method without await?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.


3 Answers

There's an easier way to do this now:

    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();
    }

With this approach, you define a method using the async keyword and wrap that method using the 'EventHandlerTaskAsyncHelper' class to generate BeginEventHandler and EndEventHandler methods to pass into the AddOnAuthenticateRequestAsync call.

like image 189
karthitect Avatar answered Sep 28 '22 04:09

karthitect


I didn't find a way to using the new C# keyword async and await, but we can still using APM pattern to use async operations in Global.asax because it implemented IHttpAsyncHandler interface. Here is a small code to demo async, here I use a WebRequst as example, in your case please use database operation instead.

    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();
    }
like image 39
ivenxu Avatar answered Sep 28 '22 03:09

ivenxu


You have to add the async version of the AuthenticateRequest yourself. Using the following code:

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);
}

The issue is then, how to implement BeginAuthenticateRequest and EndAuthenticateRequest using the new async/await features of C#. First, let's get our async version of AuthenticateRequest out of the way:

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

What we need to do next is come up with an implementation of BeginAuthenticateRequest and EndAuthenticateRequest. I followed a blog post, but derived my own implementation:

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;
}

You can read the entire linked article to see how it works, but basically IAsyncResult is implemented by Task, so all you have to do is call the callback when done.

The last bit is dead easy:

private void EndAuthenticateRequest(IAsyncResult result)
{
    // Nothing to do here.   
}
like image 23
Dave Van den Eynde Avatar answered Sep 28 '22 04:09

Dave Van den Eynde