I'm trying to understand why the following code:
async void Handle_Clicked(object sender, System.EventArgs e)
{
try
{
await CrashAsync("aaa");
}
catch (Exception exception)
{
Log($"observed exception");
Log($"Exception: {exception.Message}");
}
}
private async Task CrashAsync(string title)
{
Log($"CrashAsync ({title}) - before");
await Task.Delay(1000);
throw new Exception($"CrashAsync ({title})");
Log($"CrashAsync ({title}) - after");
}
produces the expected result:
thread #1: CrashAsync (aaa) - before
thread #1: observed exception
thread #1: Exception: CrashAsync (aaa)
but if I change it to this one:
async void Handle_Clicked(object sender, System.EventArgs e)
{
try
{
await CrashAsync("aaa").ContinueWith(async (t) =>
{
await CrashAsync("bbb");
},TaskContinuationOptions.OnlyOnRanToCompletion);
}
catch (Exception exception)
{
Log($"observed exception");
Log($"Exception: {exception.Message}");
}
}
I get the following output:
thread #1: CrashAsync (aaa) - before
thread #1: observed exception
thread #1: Exception: A task was canceled.
thread #2: unobserved exception
thread #2: System.Exception: CrashAsync (aaa) at AsyncTest.AsyncTestPage+c__async3.MoveNext () [0x000ad] in /Users/johndoe/Development/Xamarin/AsyncTest/AsyncTest/AsyncTestPage.xaml.cs:82
where:
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
Debug.WriteLine($"thread #{Environment.CurrentManagedThreadId}: unobserved exception");
foreach (var exception in e.Exception.Flatten().InnerExceptions)
{
Debug.WriteLine($"thread #{Environment.CurrentManagedThreadId}: {exception}");
}
};
The continuation condition is not satisfied so the ContinueWith task is cancelled, but why do I have unobserved exception?
You await
Task
returned byContinueWith
, so you observe exception related to thisTask
- that it was cancelled (TaskCanceledException
). But you don't observe original exception thrown by CrashAsync (so "CrashAsync aaa") exception, hence the behavior you observe.Here is sample code to get more understanding:
So in short - just await your task and catch exception if any. You don't need to use
ContinueWith
at all, because if you use await - the rest of the method is already a continuation.