The new IAsyncEnumerable interface is great, but is problematic when exposing data via an API.
Taking the code from Anthony Chu's great post the endpoint works ... until you get to more than 8162 records ... IAsyncEnumerable's buffer limit.
The JsonSerialiser is attempting to buffer the entire collection before sending it over the wire, when I would expect it to be sent as a stream.
There is a fix in the pipeline (possibly for .NET 6.0 - PR created as of 2021-04-07, see references). There is a workaround posted in the issue thread (linked below) which should work ... but ...
- What is the current best practise for streaming collections over the wire from an API (converting IAsyncEnumerable to IEnumerable apparently is bad according to Anthony Chu as it blocks the current thread
- Have any of the community found a better workaround for this?
Code to trigger issue
[HttpGet]
public async IAsyncEnumerable<int> Get()
{
for (int i = 0; i < 10000; i++)
{
yield return i;
}
}
will give the following error using .NET 5.0:
System.InvalidOperationException: 'AsyncEnumerableReader' reached the configured maximum size of the buffer when enumerating a value of type 'IAsyncEnumerableSandbox.Controllers.TestController+<Get>d__2'. This limit is in place to prevent infinite streams of 'IAsyncEnumerable<>' from continuing indefinitely. If this is not a programming mistake, consider ways to reduce the collection size, or consider manually converting 'IAsyncEnumerableSandbox.Controllers.TestController+<Get>d__2' into a list rather than increasing the limit.
The error hints at converting the IAsyncEnumerable to a list ... but there are no built-in converters.
References
- Issue 1570: Developers using JsonSerializer can asynchronously (de)serialize IAsyncEnumerable<T>
- Direct link to workaround in the above issue
- Article: Async Streams with IAsyncEnumerable in .NET Core 3
- Article: Our failed attempt at IAsyncEnumerable
Related question: Clarification on how IAsyncEnumerable works with ASP.NET Web API