I'm using an async api which supports cancellation and I'm passing to that api a CancellationToken
instance. As usual, if the cancellation is requested on the passed token, the api that I'm invoking will throws an OperationCanceledException
(this is the standard cooperative cancellation pattern of the .NET framework).
I want to be able to catch the OperationCanceledException
if and only if it is the exception raised due to the cancellation of the provided cancellation token.
The following code illustrates what I'm trying to achieve:
try
{
await _service.DoSomethingAsync(cancellationToken: token);
}
catch (OperationCanceledException ex) when ( /* here I want a condition signifying that the OperationCanceledException is caused by the cancellation of the token object */)
{
// avoid logging the exception: this is raised by design (cooperative cancellation)
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred: {0}", ex.Message);
throw;
}
For the exception filter of the code above I have basically two ideas:
IsCancellationRequested
property on the token
object: when (token.IsCancellationRequested)
CancellationToken
property on the ex
object: when (ex.CancellationToken == token)
What is the right way to do the check I want to perform ? Are the two ways showed above equivalent ? Is there a best practice ?
IMPORTANT NOTE: I know that the code showed above can be written in a more efficient way, because catching exceptions is an expensive operation. The best thing to do is probably removing the first catch
block at all, and only catching an Exception
if and only if it is not related with the cancellation of the token
object. I'm aware of that, but that's not the point of my question. I have written the code in the question that way only for clarity, because the whole point of my question is how to properly correlate an OperationCanceledException
with the CancellationToken
which has caused the exception itself.
CancellationTokenSource - This is the object responsible for creating a cancellation token and sending a cancellation request to all copies of that token. CancellationToken - This is the structure used by listeners to monitor the token's current state.
Yes, you are supposed to call ThrowIfCancellationRequested() manually, in the appropriate places in your code (where appropriate is determined by you as a programmer). Consider the following example of a simple job processing function that reads jobs from a queue and does stuff with them.
Always call Dispose before you release your last reference to the CancellationTokenSource. Otherwise, the resources it is using will not be freed until the garbage collector calls the CancellationTokenSource object's Finalize method.
I want to be able to catch the OperationCanceledException if and only if it is the exception raised due to the cancellation of the provided cancellation token.
You can't do this exactly, but you can "catch the canceled exception only if my provided token has been cancelled", which is usually good enough.
when (token.IsCancellationRequested)
is what you want.
Don't check the ex.CancellationToken
, because the method you're calling may be observing a linked cancellation token, which would be different than the one you provided.
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