How to Catch Exception in Task

What is the best way to catch exception in Task?

There are two ways you can do this, dependent on the version of the language you are using.

C# 5.0 and above

You can use the async and await keywords to simplify a great deal of this for you.

async and await were introduced into the language to simplify using the Task Parallel Library, preventing you from having to use ContinueWith and allowing you to continue to program in a top-down manner.

Because of this, you can simply use a try/catch block to catch the exception, like so:

try
{
// Start the task.
var task = Task.Factory.StartNew<StateObject>(() => { /* action */ });

// Await the task.
await task;
}
catch (Exception e)
{
// Perform cleanup here.
}

Note that the method encapsulating the above must use have the async keyword applied so you can use await.

C# 4.0 and below

You can handle exceptions using the ContinueWith overload that takes a value from the TaskContinuationOptions enumeration, like so:

// Get the task.
var task = Task.Factory.StartNew<StateObject>(() => { /* action */ });

// For error handling.
task.ContinueWith(t => { /* error handling */ }, context,
TaskContinuationOptions.OnlyOnFaulted);

The OnlyOnFaulted member of the TaskContinuationOptions enumeration indicates that the continuation should only be executed if the antecedent task threw an exception.

Of course, you can have more than one call to ContinueWith off the same antecedent, handling the non-exceptional case:

// Get the task.
var task = new Task<StateObject>(() => { /* action */ });

// For error handling.
task.ContinueWith(t => { /* error handling */ }, context,
TaskContinuationOptions.OnlyOnFaulted);

// If it succeeded.
task.ContinueWith(t => { /* on success */ }, context,
TaskContinuationOptions.OnlyOnRanToCompletion);

// Run task.
task.Start();

How to handle Task.Run Exception

When a task is run, any exceptions that it throws are retained and re-thrown when something waits for the task's result or for the task to complete.

Task.Run() returns a Task object that you can use to do that, so:

var task = Task.Run(...)

try
{
task.Wait(); // Rethrows any exception(s).
...

For newer versions of C# you can use await instead ot Task.Wait():

try
{
await Task.Run(...);
...

which is much neater.


For completeness, here's a compilable console application that demonstrates the use of await:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
class Program
{
static void Main()
{
test().Wait();
}

static async Task test()
{
try
{
await Task.Run(() => throwsExceptionAfterOneSecond());
}

catch (Exception e)
{
Console.WriteLine(e.Message);
}
}

static void throwsExceptionAfterOneSecond()
{
Thread.Sleep(1000); // Sleep is for illustration only.
throw new InvalidOperationException("Ooops");
}
}
}

Handling Exceptions Inside Task.Run

To answer your original question, before you edited it, one of the features of await is that it will "unwrap" not only the return value, but any exceptions too. So if you need to catch an exception, it will not be an AggregateException like it would be if you used .Wait() or .Result.

That's a Good Thing™

Also, it looks like Visual Studio is configured to break on all exceptions, even handled ones. This is handy (I always keep VS set like that because sometimes weird things can happen when exceptions are caught and hidden), but you just have to be aware of it. You can press F5 or F10 to continue execution and it should continue into the catch block.

How to catch exception thrown in a task in a task

Thanks for all the answers. I found a easy solution now which works for me. All i had to do is adding in my 'runtime' part of my app.config this flag

<legacyUnhandledExceptionPolicy enabled="1" />

Like described here: How to prevent an exception in a background thread from terminating an application?

I had the problem even if i was able to catch my exception my service still stops afterwards.

Handling exception from non-awaited Task


So, I just run MyAwesomeMethod (fire-and-forget)... but I also want to know if there any unhandled exceptions. But application finishes successfully without any sign of problem (exception is just swallowed).

That's not "fire and forget", then. "Fire and forget" literally means that you don't care when (or whether) the task completes (or errors).

How can I handle exception from MyAwesomeMethod(), without awaiting it or using Task.Run(...).Wait()?

Use await anyway:

Task.Run(async () => {
try {
await MyAwesomeMethod();
} catch (Exception ex) {
Console.WriteLine(ex);
}
});

Handling exception from non-awaited Task


So, I just run MyAwesomeMethod (fire-and-forget)... but I also want to know if there any unhandled exceptions. But application finishes successfully without any sign of problem (exception is just swallowed).

That's not "fire and forget", then. "Fire and forget" literally means that you don't care when (or whether) the task completes (or errors).

How can I handle exception from MyAwesomeMethod(), without awaiting it or using Task.Run(...).Wait()?

Use await anyway:

Task.Run(async () => {
try {
await MyAwesomeMethod();
} catch (Exception ex) {
Console.WriteLine(ex);
}
});

Task Exception Handling without Wait

The code you've supplied (after the edit) won't help you in handling errors thrown inside your task. It will only catch exceptions thrown in the main code block, such as in scheduling the task or getting the parameters to pass to it.

Async/Await to simplify asynchronous task control flow

If you're using C# 5 and above (bundled with VS2013), the simplest way is to use async/await, which simplifies control flow for asynchronous tasks:

public async Task DoSomething()
{
try
{
DoSyncWork();
await Task.Run(() => AsyncStuff());
}
catch (Exception ex)
{
// handle.
}
}

The compiler will automatically deconstruct the async task and return the exception to the normal catch block - regardless of whether the synchronous or async parts of the code threw the exception.

OnlyOnFaulted continuations to handle task exceptions

If you're not using C# 5, or prefer not to use async/await (because you're handling parallelism, not just asynchrony), the technique is to use Task.ContinueWith to specify a continuation in case of error:

var task = Task.Run(() => Whatever())
.ContinueWith(failedTask => HandleError(failedTask),
TaskContinuationOptions.OnlyOnFaulted);

This will cause the continuation to launch after the original task completes, but only if it threw an exception. You can use this to specify several continuation branches based on the result:

var baseTask = Task.Run(() => Whatever());            
baseTask.ContinueWith(failedTask => HandleError(failedTask),
TaskContinuationOptions.OnlyOnFaulted);
baseTask.ContinueWith(successfulTask => HandleResults(successfulTask),
TaskContinuationOptions.OnlyOnRanToCompletion);

Try/Catch Wrap Around Task.Run not Handling Exception

This is just a misleading debugger message.

What's actually happening is that the exception is being thrown, then caught by the .NET framework (not user code), and then placed on the task.

So, while technically the error message is correct (it's caught by the .NET framework - unhandled by user code), it's not very helpful in this case.

Unfortunately, there's also not a lot of alternatives for the debugger. At the point when the exception leaves user code, the debugger has no way of "looking into the future" to know that the exception will be placed on a specific task and that your code will await that task. It has to make a decision immediately whether to notify you or not, without knowing whether the task will be awaited.

How to throw/catch the inner exception from a task?

When exception is thrown in task then using Result property you will get AggregateException where the real exception is in InnerException property of this AggregateException object (your exception is wrapped by AggregateException).

To get the true exception (unwrapped exception) you can use GetAwaiter().GetResult():

var result = taskThatThrowsException.GetAwaiter().GetResult();

You can also use Result property but then you should specify some condition for exception handling;

try
{
var result = taskThatThrowsException.Result;
}
catch (AggregateException ex) when (ex.InnerException is MyException myException)
{
// use myException - it is your true unwrapped exception
}

But you should NOT block asynchronous code - you should asynchronously wait - use await and you will get your true unwrapped exception also:

var result = await taskThatThrowsException;


Related Topics



Leave a reply



Submit