How to ignore unobserved exceptions with async/await in MonoTouch?
Asked Answered
E

1

7

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:

enter image description here

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?

Esophagus answered 25/7, 2013 at 12:17 Comment(3)
You mention it "pauses" in AsyncVoidMethodBuilder. Does that mean that if you hit continue the exception is eventually swallowed by your handler? Is this a case where only the debugger halts on this exception? Also, the article you referenced includes some app.config settings for making the exception work like .NET 4. Would that be helpful?Stew
@Brad: If I hit continue, the process crashes because the exception gets re-thrown on the UI thread by the underlying UIKitSynchronizationContext. The config settings are there to make behavior stricter so they shouldn't be of help. You raised a valid point though; in previous versions, I was able to catch the exceptions in Unobserved handler even though there were thrown on the UI thread.Esophagus
There are various Unobserved handlers, for Tasks, the AppDomain etc. Try using the one specific to the UI. Await rethrows exceptions on the SynchronizationContextCalida
L
7

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) awaiting 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.

Laevorotatory answered 25/7, 2013 at 12:59 Comment(3)
Thanks, this makes perfect sense! I didn't realize I observe a task exception by awaiting it. Now if only I knew how to handle UIKit exceptions :-)Esophagus
Dan, Did you find any way to observe these UIKit exceptions?Manpower
Hi Dan, same question, have you managed to handle the UIKit exceptions ?Literati

© 2022 - 2024 — McMap. All rights reserved.