I talked about the concept of asynchronous streams before. Thanks to the introduction of the IAsyncEnumerable interface, it allowed us to combine the richness of LINQ with the readibility of async-await to asynchronously access databases, microservices and remote APIs.
[ApiController] | |
[Route("[controller]")] | |
public class ProductsController : ControllerBase | |
{ | |
public async IAsyncEnumerable<Product> GetOnSaleProductsAsync() | |
{ | |
var products = _repository.GetProductsAsync(); | |
await foreach (var product in products) | |
{ | |
if (product.IsOnSale) | |
{ | |
yield return product; | |
} | |
} | |
} | |
} |
As enumerating async streams will typically result in remote asynchronous operations it can take a while to complete. I was wondering how we could cancel these async operations?
To support this use case, IAsyncEnumerable has an extension method āWithCancellation()ā. The CancellationToken will be passed on to the IAsyncEnumerable.GetEnumerator method.
[ApiController] | |
[Route("[controller]")] | |
public class ProductsController : ControllerBase | |
{ | |
public async IAsyncEnumerable<Product> GetOnSaleProductsAsync(CancellationToken cancellationToken) | |
{ | |
var products = _repository.GetProductsAsync(); | |
await foreach (var product in products.WithCancellation(cancellationToken)) | |
{ | |
if (product.IsOnSale) | |
{ | |
yield return product; | |
} | |
} | |
} | |
} |
More information about whatās happening behind the scenes can be found here.
Remark: There are some further improvements on the way in ASP.NET Core 6 regarding consuming IAsyncEnumerable streams as mentioned in this post: https://www.tpeczek.com/2021/07/aspnet-core-6-and-iasyncenumerable.html.