I'm used to being able to perform an asynchronous pattern when handling cancellation of asynchronous operations:
public async Task InvokeAsync(CancellationToken cancellationToken)
{
using(cancellationToken.Register(handler.Stop))
{
try
{
await handler.HandleAsync();
}
catch(HandlerStoppedException ex)
{
cancellationToken.ThrowIfCancellationRequested();
throw;
}
}
}
The method calls an asynchronous component which exposes some kind of cancel mechanism. The cancellation token sets up a callback to invoke the cancel mechanism when the token signals cancellation is requested.
I can call this method in my tests to exercise its function within a timeout.
async Task TestInvoke()
{
using (var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10))
{
try
{
await InvokeAsync(timeout.Token);
}
catch (TaskCancelledException ex)
{
if (ex.CancellationToken == timeout.Token)
{
throw new TimeoutException(
"Operation failed to complete in the allowed time.", ex);
}
throw;
}
}
}
My expectation is that throwing OperationCanceledException
within an async
method will cause the Task
returned by the method to transition to the "Canceled" state. I then expect any attempts to await this cancelled task should throw a TaskCanceledException
.
In my current scenario (code very similar to above) I instead get an OperationCanceledException
when I await the task. If I examine the state of the task, I can see it is in a "Canceled" state and has no exception associated with it.
More curiously, if I call Wait()
on the task, it throws an AggregateException
containing the expected TaskCanceledException
instead.
Under what circumstances will awaiting a cancelled task throw OperationCanceledException
instead of the more typical TaskCanceledException
?
Under what circumstances will awaiting a cancelled task throw
OperationCanceledException
instead of the more typicalTaskCanceledException
?
This question is too broad. Even if one enumerated all scenarios where that happens today, it could change tomorrow.
Instead, I'll say this:
TaskCanceledException
is not "more typical". It was originally used in dynamic task-based parallelism, which has nothing to do with asynchronous programming.OperationCanceledException
is a base class for TaskCanceledException
. In your code, you should never catch TaskCanceledException
(unless you are doing dynamic task-based parallelism and need to access TaskCanceledException.Task
).Just catch OperationCanceledException
instead.
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