Several answers here has stated that it is considered a hack and anti-pattern to on-demand cancel a cancellation token without using the original CancellationTokenSource. If you still want to do this and not throw an exception like using a combination of IsCancellationRequested
and ThrowIfCancellationRequested
method, you can create an extension method to on-demand cancel a cancellation token.
public static class CancellationTokenExtensions
{
public static void ForceCancel(ref this CancellationToken cancellationToken,
Func<bool>? condition = null)
{
if (condition == null || condition.Invoke())
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(
cancellationToken);
cancellationToken = cts.Token;
cts.Cancel();
}
}
}
We use ref here since CancellationToken is a struct and want to modify the token object and must take care here since we pass a struct by value otherwise into the extension method. This is supported since C# 7.3.
If you use older C#, return the CancellationToken object and overwrite the cancellation token you passed in (probably not use this argument then since you overwrite it anyways).
Sample source code in a demo app in a Pluralsight course I am looking at right now shows how I added usage of this method inside a MVC controller action. Ignore much of the surrounding code here, point is that we can now easily cancel on demand a cancellation token. I have tested the code in Swagger API that display the controller and tested that it works.
[HttpGet]
public async Task<IEnumerable<ProductModel>> Get(CancellationToken cancelToken,
string category = "all")
{
//cancelToken.ForceCancel();
cancelToken.ForceCancel(() => category == "kayak");
using (_logger.BeginScope("ScopeCat: {ScopeCat}", category))
{
_logger.LogInformation( "Getting products in API.");
return await _productLogic.GetProductsForCategoryAsync(cancelToken,
category);
}
}
We can skip the condition argument if we want to, then the cancellation token will be canceled, as soon as possible and throw an OperationCancelled exception in your downstream code. Remember to pass the updated token downwards, if you use C# 7.3 or newer, the object is updated automatically for you using this code. You will see that IsCancellationRequested
is true, when you inspect the updated token (which now is a new struct).
Should you also keep track of the newly instantiated CancellationTokenSource inside the cts variable in the method ? This could also be an option, letting the extension method return CancellationTokenSource
you created here and save this to a var in the calling code. That object is a class by the way.