Suppose I have the following code:
private static void Run()
{
TaskScheduler.UnobservedTaskException += delegate { Console.WriteLine("Unobserved task exception!"); };
try
{
RunAsync().Wait();
}
catch (Exception)
{
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Thread.Sleep(Timeout.InfiniteTimeSpan);
}
private static async Task RunAsync()
{
var task1 = ThrowAsync();
var task2 = ThrowAsync();
await task1;
await task2;
}
private static async Task ThrowAsync()
{
throw new Exception("Test exception");
}
This code outputs Unobserved task exception!
because the exception in task2
is not observed.
My question is the following: is there any way to programmatically determine which task had an unobserved exception? For example, I want to get a stack trace for a method which invoked a task or something like this:
Unobserved exception: task2 in RunAsync()
Sadly, exception stack trace is not enough. The code above is just a demonstration, in a real-world application I sometimes have unobserved task exceptions with a stack trace like this:
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.NullReferenceException: Object reference not set to an instance of an object.
at System.Web.HttpApplication.get_CurrentModuleContainer()
at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error)
One would be able to tell which Task instance had its exception unobserved. That would be task2
under the second await
await task1;
await task2;
because the first await
"observes" the result of task1
.
Then if the event handler is modified to presenting the actual Task exception that TaskScheduler.UnobservedTaskException
provides
TaskScheduler.UnobservedTaskException += delegate(object o, UnobservedTaskExceptionEventArgs ea)
{
Console.WriteLine($"Unobserved task exception! {ea.Exception.ToString()}");
};
then the failing region of the Task code can be tracked down by observing the exception's stack trace:
Unobserved task exception!
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. (Test exception)
---> System.Exception: Test exception
at ConsoleApp1.Program.ThrowAsync() in C:\Users\sergepavlov\Desktop\ConsoleApp1\ConsoleApp1\Program.cs:line 42
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.Exception: Test exception
at ConsoleApp1.Program.ThrowAsync() in C:\Users\sergepavlov\Desktop\ConsoleApp1\ConsoleApp1\Program.cs:line 42
<---
Hope that makes sense.
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