Asynchrnous Programming in C# Cheat Sheet

Tip: Dont go for Async Void

You get possibly three return types for async methods and those would be

  • Task
  • Task < T >
  • void

Its always better if you can avoid the void

Reason:

Async Void methods were made possible so one can have async event handlers. Exceptions thrown out of these are actually handled in the Synchronization context that was active at that time, meaning you wont be able to "catch" it with a "catch". You can definitely catch those in App.UnhandledException or similiar all unhandled exception catching scenarios. Plus, its not testable too.

If you go for returning Task you will see your async methods are returning a Task object which essentially has the exceptions noted inside of it.

Workaround:

In case of stuff like async event handlers, the best thing to do would be is to put the actual code logic in a separate awaited method so you can test it whenever you want.

Tip: Once Async always go async

Async codes are written better if they are written from the top to the bottom in an all async paradigm, meaning its always better to wrap an async method in another async method all the way to the bottom. If you wrap up a little async code in your sync code context, you might end up in a deadlock.

Reason and Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class DeadlockDemo
{
private static async Task DelayAsync()
{
await Task.Delay(1000);
}
// This method causes a deadlock when called in a GUI or ASP.NET context.
public static void Test()
{
// Start the delay.
var delayTask = DelayAsync();
// Wait for the delay to complete.
delayTask.Wait();
}
}

This piece of code would end up in a deadlock in GUI or ASP.net apps. Because when you await a Task the current context is captured so it can be resumed on the current context after the awaiting is done. The context is usually the current SynchronizationContext which is essentially the TaskScheduler. In Asp.net or GUI app youre only supposed to run a single chunk of code at a time. In this case the DelayAsync await is completed it is trying to complete the rest of the code after await in the captured context. This context has already a thread in it and waiting for the async call to be finished. They are waiting on each other = deadlock.

In case of a console app, this would execute just fine. Because it has a thread pool SynchronizationContext so it would execute the rest of the async method in a separate thread.

A good thing to remember here is that if you await a async method only the first exception occured would be rethrown. If you block in synchronously you'd get an AggregateException with all the exceptions in it

Tip: Configuring await context

When you have a lot of incy wincy bits of async code, your GUI app might end up in a situation where most of the time its busy handling those async events. This can lead to performance issues.

Solution and Example:

Using ConfigureAwait at the end of your async call might help you in this case. Follow the following example:

1
2
3
4
5
6
7
8
9
10
async Task MyMethodAsync()
{
// Code here runs in the original context.
await Task.Delay(1000);
// Code here runs in the original context.
await Task.Delay(1000).ConfigureAwait(
continueOnCapturedContext: false);
// Code here runs without the original
// context (in this case, on the thread pool).
}

You can definitely see here that we are denying to run the rest of the async method after the await in the same context. Now it would use a thread pool synchrnizing context for your code and esssentially would make your code deadlock free and a tad smoother. Very handy for UWP app people.

Warning

For GUI people, dont use ConfigureAwait everywhere! Please only use it when the rest of the code doesnt handle any GUI events (databound update, GUI updates) and for ASP.net people, dont use it if the rest of the code uses HttpContext of that time.

And finally, If you're not a TLDR; guy and need more please read this