I have a method that creates some Tasks, and then waits on them with WaitAll before returning. The problem is, if those tasks got canceled, then WaitAll throws an AggregateException containing lots of TaskCanceledExceptions.
That means that WaitAll will throw exceptions in two different circumstances:
The latter fits squarely into the definition of a vexing exception: it's an exception thrown in a completely non-exceptional circumstance, so I have to catch it in order to resume normal control flow. Fortunately it's easy to catch, right? Just add catch (AggregateException)
and -- oh wait, that's the same type that gets thrown when there's a fatal error.
I do need to wait for the tasks to finish running before I return (I need to know that they're no longer using their database connections, file handles, or anything else), so I do need the WaitAll or something similar. And if any of the tasks faulted, I do want those exceptions to propagate as unhandled exceptions. I just don't want exceptions for cancel.
How can I prevent WaitAll
from throwing exceptions for canceled tasks?
There's 2 likely reasons that a TaskCanceledException would be thrown: Something called Cancel() on the CancellationTokenSource associated with the cancellation token before the task completed. The request timed out, i.e. didn't complete within the timespan you specified on HttpClient. Timeout .
The CancellationToken is used in asynchronous task. The CancellationTokenSource token is used to signal that the Task should cancel itself. In the above case, the operation will just end when cancellation is requested via Cancel() method.
For canceling, we use CancellationTokenSource object.
The AggregateException
provides a Handle
method that can be used for these situations. If for example you want to ignore TaskCanceledException
you can do:
var all = new AggregateException( new NullReferenceException(), new TaskCanceledException(), new TaskCanceledException(), new InvalidOperationException(), new TaskCanceledException()); try { throw all; } catch (AggregateException errors) { errors.Handle(e => e is TaskCanceledException); }
If all the exceptions are of type TaskCanceledException
, the Handle
method will not throw any exception; otherwise a new AggregateException
containing only the unhandled exceptions will be thrown.
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