If you've stumbled upon this post it most likely means that you're looking for a way to call an async method from one of the default handlers available from the Global.asax file of your ASP.NET Web Application.
Such handlers include:
- Application_BeginRequest, fired when a request for the web application comes in.
- Application_AuthenticateRequest, fired just before the user credentials are authenticated. You can specify your own authentication logic over here.
- Application_AuthorizeRequest, fired on successful authentication of user’s credentials. You can use this method to give authorization rights to user.
- Application_ResolveRequestCach, fired on successful completion of an authorization request.
- Application_AcquireRequestState, fired just before the session state is retrieved for the current request.
- Application_PreRequestHandlerExecute, fired before the page framework begins before executing an event handler to handle the request.
- Application_PostRequestHandlerExecute, fired after HTTP handler has executed the request.
- Application_ReleaseRequestState, fired before current state data kept in the session collection is serialized.
- Application_UpdateRequestCache, fired before information is added to output cache of the page.
- Application_EndRequest, fired at the end of each request.
The problem
As you probably already know, in order to perform an asynchronous call within a method that whole method must be marked as async: however, those Global.asax's event handlers cannot be made async, otherwise the following exception will be thrown:
An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>.
The fix
Luckily enough, there is a simple yet effective workaround that can be used to launch an async method from within the Global.asax file, binding it to the same events handled by the above methods. We just have to create a separate async method to host our async call:
1 2 3 4 5 6 7 8 9 10 11 |
/// <summary> /// Call async tasks at the start of each request from Global.asax /// </summary> private async Task Application_BeginRequestAsync(object sender, EventArgs e) { var app = (HttpApplication)sender; var ctx = app.Context; var result = await MyAsyncMethod(); // todo... } |
... and then register it within the main application's lifecycle in the following way:
1 2 |
var wrapper = new EventHandlerTaskAsyncHelper(Application_BeginRequest_Async); AddOnBeginRequestAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler); |
As we can see from the above example, I've called the async method with the same name of the default handler I wanted to reproduce (Application_BeginRequest -> Application_BeginRequestAsync).
As for the binding, it can be done inside the Global.asax class constructor, usually Global or MvcApplication depending on the Visual Studio edition and/or ASP.NET Web Application Template used:
1 2 3 4 5 6 |
public MvcApplication() { // Call async tasks at the start of each request from Global.asax var wrapper = new EventHandlerTaskAsyncHelper(Application_BeginRequest_Async); AddOnBeginRequestAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler); } |
Alternative workarounds
In case you want to consider a different approach you could take a look at AsyncUtil, a small C# helper class I wrote a while ago that allows to securely run async methods as sync and vice-versa: however, using such class to achieve the behaviour discussed within this post would likely be overkill, since everything can be handled with a very minimal amount of additional code.
Conclusion
That's it, at least for now: I hope that this small post will help those ASP.NET developers looking for a way to call async methods from their ASP.NET Web Application's Global.aspx file.
For additional info regarding the C# async/await pattern and its usage in ASP.NET and ASP.NET Core, check out the following posts:
- Async, Await, Lock, Wait and SynchronizationContext in ASP.NET Core
- AsyncUtil – C# Helper class to run async methods as sync and vice-versa
- ASP.NET Core C# – How to lock an async method according to custom IDs
Thanks for sharing this