Daily Knowledge Drop
When iterating over a collection or items, the TakeWhile
method can be used in conjunction with a CancellationToken
to successfully stop iterating if the parent process is cancelled.
No CancellationToken
Generally, when iteration through a collection, a foreach
(or for
) loop is used:
async Task ExecuteLoopNoCancel()
{
// generate a collection of 100 items
var iterationItems = Enumerable.Range(0, 100);
// iterate through the 100 items
foreach (var item in iterationItems)
{
Console.WriteLine($"Processing item: {item}");
await Task.Delay(500);
}
}
Calling the above /ExecuteLoopNoCancel
endpoint has the following output:
Processing item: 0
Processing item: 1
Processing item: 2
Processing item: 3
.
.
The issue with the above, and especially in an endpoint which can be cancelled at any time, is that if the parent process is cancelled, the iteration of the collection will continue
.
If the endpoint is called (from Postman, for example), and the request is cancelled
, the loop will continue to execute in the background (and output to the console), as it is being executed asynchronously
.
With CancellationToken
To correctly cancel the iteration
when the parent process is cancelled, a CancellationToken
should be passed from the top of the stack all the way down to the loop:
// pass in a CancellationToken
async Task ExecuteLoop(CancellationToken cnlTkn)
{
var iterationItems = Enumerable.Range(0, 100);
// only loop while the CancellationToken is not cancelled
foreach(var item in iterationItems
.TakeWhile(_ => !cnlTkn.IsCancellationRequested))
{
Console.WriteLine($"Processing item: {item}");
await Task.Delay(500);
}
}
- A
CancellationToken
token is passed into the endpoint - this is linked to client, so if the request is cancelled from the client side, the CancellationToken is "notified" of the cancellation - In the foreach loop, the
TakeWhile
method is called, with aCancellationToken
passed in as a parameter
Now, when the endpoint is called (from Postman, for example), and the request is cancelled
, the CancellationToken is marked as cancelled (IsCancellationRequested is set to true), and the iteration will stop.
Notes
When performing iterations over a collection, where it makes sense (in situations when the calling process can be cancelled, such as in an endpoint), a CancellationToken
instance should always be used. This ensures any iterations being done asynchronously will be cancelled, ensuring resources are not being unessacary used.
References
Daily Drop 235: 16-01-2023
At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.
The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.