I've written a custom ASP.NET control and I just updated it to have an async Load event handler. Now I'm getting this error:
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 page does have the <%@ Page Async="true" %>
tag already. So I take it that controls can't have async load event handlers.
Where can I find a comprehensive list of events in the ASP.NET webforms lifecycle that are allowed to be async?
The solution is extremely simple: just mark the event handler as async. You should never use async void methods, instead use async Task or async Task<T1,...>. The exception, apparently, is event handlers. And it kind of makes sense: an event handler is designed to be called asynchronously.
Master define Page_Load events and one or both of them are asynchronous, the order of execution can't be guaranteed.
All I/O in ASP.NET Core is asynchronous. Servers implement the Stream interface, which has both synchronous and asynchronous overloads. The asynchronous ones should be preferred to avoid blocking thread pool threads.
These include initialization, instantiating controls, restoring and maintaining state, running event handler code, and rendering. It is important for you to understand the page life cycle so that you can write code at the appropriate life-cycle stage for the effect you intend.
Damian Edwards from the ASP.NET team gave this answer:
Async void event handlers in web forms are only supported on certain events, as you've found, but are really only intended for simplistic tasks. We recommend using PageAsyncTask for any async work of any real complexity.
Levi Broderick from the ASP.NET team gave this answer:
Async events in web applications are inherently strange beasts. Async void is meant for a fire and forget programming model. This works in Windows UI applications since the application sticks around until the OS kills it, so whenever the async callback runs there is guaranteed to be a UI thread that it can interact with. In web applications, this model falls apart since requests are by definition transient. If the async callback happens to run after the request has finished, there is no guarantee that the data structures the callback needs to interact with are still in a good state. Thus why fire and forget (and async void) is inherently a bad idea in web applications.
That said, we do crazy gymnastics to try to make very simple things like Page_Load work, but the code to support this is extremely complicated and not well-tested for anything beyond basic scenarios. So if you need reliability I’d stick with RegisterAsyncTask.
So I think the answer to my question is: "That's the wrong question."
The right question would be "How should I be async in my ASP.NET Web Forms application?" And the answer is to insert this snippet inside your aspx code-behind file:
this.RegisterAsyncTask(new PageAsyncTask(async cancellationToken => { var result = await SomeOperationAsync(cancellationToken); // do something with result. }));
This same trick works inside ASP.NET custom controls, just use this.Page.RegisterAsyncTask
instead.
This page explains how life cycle event handling in asynchronous pages differs from those of synchronous pages in ASP.NET 2.0 (Figure 2 is especially helpful):
Wicked Code: Asynchronous Pages in ASP.NET 2.0
You may also find this SO question of use (it talks about the same error message):
async keyword and choice of the TaskScheduler
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With