In Windows 8 and now Windows Phone 8 the async/await keywords give us a simpler, more concise way of managing asynchronous code.
But, what happens when stuff goes wrong unintentionally, unhandled exceptions occurring when using these constructs?
The short answer is of course it depends!
Let’s take the following async void method. If you authored and called this method in a Windows 8 app without doing anything else, it would crash the process, no ifs or buts, crash.
You will read a lot of guidance on the web that says simple “don’t author async void methods!” for this very reason, but they are there for a purpose, fire and forget event handlers. Often these handlers are built into the lifecycle of a page’s execution so you are actually starting from within an async void to begin with.
Some solutions then dictate wrapping all of our code in a try/catch or in some sort of Invoke method which enables us to centralize the execution of code from async voids. Messy and error prone to say the least.
Let’s look at another scenario, not awaiting an async method call as follows where the method implementation of Go() calls the method Test() without awaiting the call.
Now, you would get a compiler warning about this, the warning would urge you to await the call, but you might think “i don’t care , i don’t need to await it as it’s fire and forget so i’ll just carry on”. Might sound sane, but exceptions are simply swallowed, hidden and you will never know about them if you didn’t do anything else, not pretty.
So, we have 2 problems in summary:
- unhandled exceptions within async void methods will crash the process.
- unhandled exceptions within unawaited async calls will be swallowed and never surfaced.
The solution is to ensure you can handle unhandled exceptions from these 2 additional scenarios in a global way alongside the normal unhandled exception handler for the application.
Essentially, we need to update our App constructor and add a couple of handlers.
The custom AsyncSynchronizationContext class essentially gets registered to allow you to hook into any unhandled exceptions occuring on async void calls made from the same originating thread (the UI thread in our instance).
Thanks to Mark Young for his work on this.
In addition you can see we now have a global ExceptionHandler class who’s job it is to deal with and surface any unhandled exceptions where possible.
Note that the UnobservedTaskException event is not possible to surface on the UI, your only option here is to log. To avoid this ever firing, ensure you always await async calls as suggested above.
With Windows Phone 8 you can use a MessageBox or RadMessageBox (if you are using the excellent Telerik Windows Phone controls) to surface the message, code below for ExceptionHandler is for Windows 8 only.
The code sample below uses Caliburn.Micro for the easy Execute.OnUIThread marshalling call, but you can also make a call to CoreDispatcher.RunAsync but it’s a bit more verbose.
Note that it’s entirely up to you what you do here, but the options are really to log and/or surface the exception information as your application requires it.
Logging can be done for example with markedup.com on Windows 8 and flurry.com on Windows Phone 8.
In summary, if you do nothing and liberally make use of async/awaits within you code you are likely to have an application that will either crash or will have problems which aren’t easily surfaced or understood.
I agree, these issues should be better taken care of by the framework and/or templates, but in the mean time we have to implement this sort of solution to improve the quality of our apps and get visibility on any problems.