Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

async void event handlers - clarification?

I'm trying to understand the reason why is it bad to do: (notice, context here is asp.net, regardless the plain reason that async void can't be tracked)

 public async void Page_Load(object sender, EventArgs e)
{
 ...
}

Well , after investigating a bit I saw few different reasons :

  • Damian Edwards Says here that:

    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 Says here that:

    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.

  • This site says:

    As we know our page life cycle has a set of events that gets fired in a predefined order and next event will be fired only when the last event completes. So if we use the above way of async Page_Load, this event will be fired during page life cycle event once it reaches to async, current thread gets free and a another thread got assigned to complete the task asynchronously, but the ASP.NET cannot execute the next event in life cycle because Page_Load has not been completed yet. And underlying synchronization context waits till the asynchronous activity completes. Then only the next event of page lifecycle will be fired which makes the whole process in synchronous mode only.

  • This site says

    when the return type is void, the caller might assume the method is complete by the time it returns. This problem can crop up in many unexpected ways. It’s usually wrong to provide an async implementation (or override) of a void-returning method on an interface (or base class). Some events also assume that their handlers are complete when they return.

I see here very different (non-overlapping) reasons.

Question :

What is the glory/true reason for which we shouldn't write public async void Page_Load(object sender, EventArgs e) ?


nb, I also don't know why it is a problem since 4.5 does use the UseTaskFriendlySynchronizationContext which its aim is to support:

protected async void Page_Load(object sender, EventArgs e){...}

like image 936
Royi Namir Avatar asked May 01 '14 11:05

Royi Namir


People also ask

Can event handlers be async?

You can register both synchronous and asynchronous event handlers concurrently to the same event. The Event Manager framework executes the registered event handlers in whichever mode you configure them to operate, always executing synchronous event handlers first.

Which async method can be used for event handlers?

NET events do not support async Task as a result type! Instead, you have to cast event handlers as async void if you want to run async code inside of an event handler method and to comply with the classic .

Can async void be awaited?

For methods other than event handlers that don't return a value, you should return a Task instead, because an async method that returns void can't be awaited. Any caller of such a method must continue to completion without waiting for the called async method to finish.

How does async void work in C#?

An async void method will capture the current SynchronizationContext at the beginning of the method, and any exceptions from that method will be captured and raised directly on that captured context. In the most common scenarios, this will cause an application-level exception, usually a crash.


2 Answers

The articles you link to make the reasons pretty clear. Don't use it because it isn't reliable beyond the most basic of scenarios. There is only so much async tracking trickery we can pull in the synchronization context on async void methods. We did work to make those basic scenarios work, but our general guidance is to avoid using them and instead explicitly register async work.

like image 81
Damian Edwards Avatar answered Oct 20 '22 01:10

Damian Edwards


I haven't verified this, but I think it's OK to use async void Page_Load(...) in ASP.NET 4.5 WebForms, for as long as the page has <%@ Page Async="true" ... %> declaration.

I think so based on the implementation of AspNetSynchronizationContext.OperationStarted, which is called when any async void method is invoked on a thread with AspNetSynchronizationContext. Here's a relevant comment:

 // If the caller tries to kick off an asynchronous operation while we are not
 // processing an async module, handler, or Page, we should prohibit the operation.

Apparently, pages with Async="true" do not violate this requirement, and the HTTP request processing isn't going to be completed until all pending operations have completed, including async void ones.

like image 29
noseratio Avatar answered Oct 19 '22 23:10

noseratio