TimeoutException, TaskCanceledException C#
Asked Answered
P

1

7

I am new to C# and I find exceptions a bit confusing... I have a web app with the following code:

try
{
    //do something
}
catch (TimeoutException t)
{
    Console.WriteLine(t);
}
catch (TaskCanceledException tc)
{
    Console.WriteLine(tc);
}
catch (Exception e)
{
    Console.WriteLine(e);
}

When I debug the code, it throws the e Exception, the most general one and when I hover over the exception info it turns out that it's the TaskCanceledException. Why isnt the TaskCanceledException caught? If the exception was a TimeoutException would it catch the TimeoutException or would it also catch the Exception? Why is that?

Pelpel answered 21/7, 2014 at 13:35 Comment(2)
Are you sure it isn't an AggregationException thrown from a Task object? show us the throwing callWillowwillowy
...yes, it's the System.AggregateException and the InnerException is the System.Threading.Task.TaskCanceledException.Pelpel
W
6

When catching an Exception, you have to make sure it is exactly the exception being thrown. When using Task.Run or Task.Factory.Startnew and generally involving an exception being thrown from a Task (unless the task is being awaited with the await keyword), the outer exception you're dealing with is an AggregateException, because a Task unit may have child tasks which may also throw exceptions.

From Exception Handling (Task Parallel Library):

Unhandled exceptions that are thrown by user code that is running inside a task are propagated back to the joining thread, except in certain scenarios that are described later in this topic. Exceptions are propagated when you use one of the static or instance Task.Wait or Task.Wait methods, and you handle them by enclosing the call in a try-catch statement. If a task is the parent of attached child tasks, or if you are waiting on multiple tasks, then multiple exceptions could be thrown. To propagate all the exceptions back to the calling thread, the Task infrastructure wraps them in an AggregateException instance. The AggregateException has an InnerExceptions property that can be enumerated to examine all the original exceptions that were thrown, and handle (or not handle) each one individually. Even if only one exception is thrown, it is still wrapped in an AggregateException.

So, in order to deal with that, you have to catch AggregateException:

try
{
    //do something
}
catch (TimeoutException t)
{
    Console.WriteLine(t);
}
catch (TaskCanceledException tc)
{
    Console.WriteLine(tc);
}
catch (AggregateException ae)
{
   // This may contain multiple exceptions, which you can iterate with a foreach
   foreach (var exception in ae.InnerExceptions)
   {
       Console.WriteLine(exception.Message);
   }
}
catch (Exception e)
{
    Console.WriteLine(e);
}
Willowwillowy answered 21/7, 2014 at 13:49 Comment(3)
Ok. Now my app should timeout, but instead of a TimeoutException I get this AggregateException with TaskCanceledException inside. How do I get the program to catch the TimeoutException?Pelpel
basically is it possible for a TimeoutException to be thrown instead of TaskCanceledException?Pelpel
No, it isn't possible. An AggregateExcception is thrown from a Task because it may also contain children tasks. Its simply a wrapper.Willowwillowy

© 2022 - 2024 — McMap. All rights reserved.