Source: https://docs.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-5.0
ASP.NET Core 3.0 and later, returning IAsyncEnumerable<T> from an action:
- No longer results in synchronous iteration.
- Becomes as efficient as returning IEnumerable<T>.
ASP.NET Core 3.0 and later buffers the result of the following action before providing it to the serializer:C#Copy
public IEnumerable<Product> GetOnSaleProducts() =>
_context.Products.Where(p => p.IsOnSale);
Consider declaring the action signature’s return type as IAsyncEnumerable<T> to guarantee the asynchronous iteration. Ultimately, the iteration mode is based on the underlying concrete type being returned. MVC automatically buffers any concrete type that implements IAsyncEnumerable<T>.
Consider the following action, which returns sale-priced product records as IEnumerable<Product>:C#Copy
[HttpGet("syncsale")]
public IEnumerable<Product> GetOnSaleProducts()
{
var products = _repository.GetProducts();
foreach (var product in products)
{
if (product.IsOnSale)
{
yield return product;
}
}
}
The IAsyncEnumerable<Product> equivalent of the preceding action is:C#Copy
[HttpGet("asyncsale")]
public async IAsyncEnumerable<Product> GetOnSaleProductsAsync()
{
var products = _repository.GetProductsAsync();
await foreach (var product in products)
{
if (product.IsOnSale)
{
yield return product;
}
}
}
Both of the preceding actions are non-blocking as of ASP.NET Core 3.0.