162

I know it is considered generally a bad idea to use fire-and-forget async void methods to start tasks, because there is no track of the pending task and it is tricky to handle exceptions which might be thrown inside such a method.

Should I generally avoid async void event handlers, as well? For example,

private async void Form_Load(object sender, System.EventArgs e)
{
        await Task.Delay(2000); // do async work
        // ...
} 

I can rewrite it like this:

Task onFormLoadTask = null; // track the task, can implement cancellation

private void Form_Load(object sender, System.EventArgs e)
{
        this.onFormLoadTask = OnFormLoadTaskAsync(sender, e);
} 

private async Task OnFormLoadTaskAsync(object sender, System.EventArgs e)
{
        await Task.Delay(2000); // do async work
        // ...
} 

What are the underwater rocks for async event handlers, besides possible re-entrancy?

avo
  • 10,101
  • 13
  • 53
  • 81
  • You should but you can't. Besides that, all the cares you must take when using async void are already required by UI event handlers. – Paulo Morgado Oct 17 '13 at 08:15
  • And reentrancy happens because of asynchronous operations fired by the event handler and not by the use of async-await by itself. – Paulo Morgado Oct 17 '13 at 08:18

4 Answers4

196

The guideline is to avoid async void except when used in an event handler, so using async void in an event handler is OK.

That said, for unit testing reasons I often like to factor out the logic of all async void methods. E.g.,

public async Task OnFormLoadAsync(object sender, EventArgs e)
{
  await Task.Delay(2000);
  ...
}

private async void Form_Load(object sender, EventArgs e)
{
  await OnFormLoadAsync(sender, e);
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • I'm curious... is there a reason why you don't just change `Form_Load`'s access to `public`? It seems like the code would be less verbose that way. – InteXX Feb 18 '15 at 07:31
  • Oops, never mind... VBer trying to read C# here... I just noticed the return type of `OnFormLoadAsync`. I see now that this makes for a handy trick. Thanks. – InteXX Feb 18 '15 at 07:33
  • All that said, could you have a look and offer an opinion [here](http://stackoverflow.com/q/28524372/722393). Thanks! – InteXX Feb 18 '15 at 07:37
  • In WPF is it fine to mark routed event handlers with async? I am not sure how the `Handled` flag on the event args would be checked in such a case... – Alex Hope O'Connor Nov 05 '18 at 06:10
  • 2
    @AlexHopeO'Connor: The `Handled` flag *must* be set synchronously; it's not possible to use `async` to make a decision on whether the event is handled or not. – Stephen Cleary Nov 05 '18 at 13:00
  • @StephenCleary so would it be alright to fire off an async void from the top level event handlers for command bindings in WPF? Been reading this: https://msdn.microsoft.com/en-us/magazine/dn630647.aspx But I have been using CommandBinding and RoutedUICommand in my application and was wondering how to best execute my commands asynchronously and provide things like user cancellation etc – Alex Hope O'Connor Nov 06 '18 at 02:30
  • 2
    @AlexHopeO'Connor: It's been a while since I've worked with a WPF app, but I've used solutions similar to that in the past. I.e., make the `ICommand.Execute` method `async void`; I consider this acceptable since `ICommand.Execute` is *logically* an event handler. – Stephen Cleary Nov 06 '18 at 17:35
  • @StephenCleary Is your answer also will be good in case there is try-catch inside the method called by the timer? Is there a chance which the logging inside the catch clause will not be written? I'm asking this, since it always had been said that in case of "async void" there is no guarantee for the logging to work. Thanks in advance! – Nuriel Zrubavely Aug 26 '20 at 21:08
  • 1
    @NurielZrubavely: If there's logging in the catch clause, it should be run on exception. However, if you're doing "fire and forget" on ASP.NET, then any `async void` method may not complete. – Stephen Cleary Aug 26 '20 at 22:18
61

Should I generally avoid async void event handlers, as well?

Generally event handlers are the one case where a void async method is not a potential code smell.

Now, if you do need to track the task for some reason then the technique you describe is perfectly reasonable.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
8

If you use ReSharper, a free ReCommended Extension could be helpful for you. It analyzes the "async void" methods and highlights when used inappropriately. The extension can distinguish different usages of async void and provide appropriated quick fixes described here: ReCommended-Extension wiki.

Alexander Zwitbaum
  • 4,776
  • 4
  • 48
  • 55
7

Yes, generally async void of event handlers is the only case. If you want to know more about it you can check out a great video here at channel 9

The only case where this kind of fire-and-forget is appropriate is in top-level event-handlers. Every other async method in your code should return "async Task".

here is the link

Vimes
  • 10,577
  • 17
  • 66
  • 86
Idrees Khan
  • 7,702
  • 18
  • 63
  • 111
  • 1
    The '_top-level event-handlers_' is a important hint. When using async void event handler on lower level event handler it can cause huge problems with not caught exceptions. – Portikus Nov 06 '17 at 10:27
  • Thanks for the video link, very useful – lsp Nov 29 '18 at 11:12
  • 2
    The link is broken, it may have been moved here: https://learn.microsoft.com/en-us/shows/three-essential-tips-for-async/tip-1-async-void-top-level-event-handlers-only – mshwf Dec 07 '22 at 16:05