In previous versions of MonoTouch, I used to do this to ignore unobserved exceptions:
TaskScheduler.UnobservedTaskException += delegate(object sender, UnobservedTaskExceptionEventArgs e) {
Console.WriteLine (e);
e.SetObserved ();
};
Whether it is a good practice is debatable but I'd like to know to achieve the same effect with async
/await
keywords now officially supported in Xamarin.iOS 6.4.
Here is the code I use for testing:
async void OnClick (object sender, EventArgs e)
{
await Task.Run (() => { throw new Exception (); });
}
When I run it, debugger pauses in AsyncVoidMethodBuilder
:
I read that .NET 4.5 supposedly changed the behaviour so unobserved exceptions don't crash the app—but this doesn't help if exceptions are posted to UIKit synchronisation context where I can't handle them.
Is there a way to ignore unobserved exceptions from await
in MonoTouch?
This is the correct behavior of async void
methods: they are supposed to raise the exception on the SynchronizationContext
that was active at the time the async void
method started.
The change you mentioned in .NET 4.5 is dealing only with unobserved task exceptions, and does not apply to async void
methods.
In the (Microsoft) .NET world, different SynchronizationContext
implementations have different top-level error handling. WPF, WinForms, and ASP.NET all have different ways of handling that error, usually as part of an Application
type.
I looked through Mono's UIKit API - though I'm not a regular Mono user - and couldn't find any top-level error handling in UIApplication
, and UIKitSynchronizationContext
looks like it's not public (or at least not documented).
Another way of looking at this problem: the exception handling behavior for async void
methods is designed to be just like event handlers would have (for more info, see my MSDN article). So you can answer the question with another question: in UIKit, how would you handle this exception?
void OnClick (object sender, EventArgs e)
{
throw new Exception();
}
You would handle your async void
exception in exactly the same way.
Alternatively, if you want to keep using UnobservedTaskException
, you can simply not observe the task exception (in your async void
code, Task.Run
returns a task that gets an exception, and you're observing it by using await
):
void OnClick (object sender, EventArgs e)
{
Task.Run(() => { throw new Exception(); });
}
However, I recommend using async void
for event handlers and (eventually) await
ing all your tasks. This will ensure you aren't getting any "silent errors" (ignored task exceptions) where your program just stops working correctly and you don't know why.
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