user3009804
user3009804

Reputation: 349

Task Exception Management c#

I run a solution that contains 2 projects: the app and the sdk.

Through the app I create an instance of the sdk so the app can start. The problem is that when I get an Exception in a part of code running inside of a Task, no Unhandled Exception is thrown so my app keeps running and doesn't realise an unexpected is happening in the SDK.

I am registered to AppDomain.CurrentDomain.UnhandledException's event in the App and SDK, but as said when the Exception is thrown in a Task, the event handler isn't called.

Is there something that I am missing?

Upvotes: 4

Views: 678

Answers (3)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149538

The problem is that when I get an Exception in a part of code running inside of a Task, no Unhandled Exception is thrown so my app keeps running and doesn't realise an unexpected is happening in the SDK.

That's not entirely correct (thanks to @l3arnon for the correction): Task will propagate the exceptions in both .NET 4.0 and .NET 4.5, and will fire the UnobservedTaskException. The difference between the two is that .NET 4.5 will quietly swallow the exception after it fires, as opposed to .NET 4.0 which will crash your process if that event goes unhandled.

You can change back to the .NET 4.0 behavior via your 'app.configandThrowUnobservedTaskExceptions`

There are a couple of other ways you can tackle this problem:

  1. use await Task.Run in your code. await will unwrap your exception from inside the task.
  2. If you don't want to await and want to use a "Fire and Forget" approach, you can attach a continuation:

    Task.Run(() => {}).ContinueWith(task => { */ Handle Exceptions here */ },
                                    TaskContinutationOptions.OnlyOnFaulted);
    

Upvotes: 3

i3arnon
i3arnon

Reputation: 116548

Both answers are somewhat (but not fully) complete.

Asynchronous

The best way to handle a faulted task is to asynchronously wait for it to complete using await. This will rethrow the original stored exception:

try
{
    await task;
}
catch (Exception e)
{
    // handle exception
}

Synchronous

If you can't do that (or don't want to) you can also use task.Wait() which waits synchronously and throws an AggregateException containing the original exception in InnerExceptions or register a continuation that handles it (i.e. task.ContinueWith(t => // handle exception))

UnobservedTaskException

In .Net 4.0 an unobserved Task exception would bring down the entire process. The TaskScheduler.UnobservedTaskException event was the last option to handle the exception before the crash (very similar to the case of UnhandledException). In .Net 4.5 this type of exception no longer crashes the app, but the event is still raised.

If you want to crash the app in this case (and I doubt you do) you can set <ThrowUnobservedTaskExceptions enabled="true"/> as Yuval pointed out. You can instead use the event itself to handle the exception which isn't optimal for 2 reasons:

  1. .Net decides your task's exception was unobserved only when the task is garbage collected which could happen anytime (or never, if you don't release all references to it). Until then you may still handle the exception yourself, so it isn't yet unobserved.
  2. You get the exception, but not the task, and it can be difficult to know the real origin of the problem without it.

Conclusion

Make sure to await your tasks to handle exceptions as they occur. Also use UnobservedTaskException as a catch all in case you missed a task.

Upvotes: 5

Jcl
Jcl

Reputation: 28272

When a Task throws an unhandled exception, its execution is terminated and you can check for IsFaulted and Exception properties on the original Task object.

More info about those properties here and here, and there's an article devoted to exception handling in Tasks on the MSDN

You also have the UnobservedTaskException event on TaskScheduler. I've never used it myself, but reading about it, it should be similar to the UnhandledException event on AppDomain. Check it on MSDN

Upvotes: 3

Related Questions