MVC doesn't buffer IAsyncEnumerable types when using System.Text.Json

In ASP.NET Core 5, MVC added support for output formatting IAsyncEnumerable<T> types by buffering the sequence in memory and formatting the buffered collection. In ASP.NET Core 6, when formatting using System.Text.Json, MVC no longer buffers IAsyncEnumerable<T> instances. Instead, MVC relies on the support that System.Text.Json added for these types.

In most cases, the absence of buffering would not be observable by the application. However, some scenarios may have inadvertently relied on the buffering semantics to correctly serialize. For example, returning an IAsyncEnumerable<T> that's backed by an Entity Framework query on a type with lazy-loaded properties can result in concurrent query execution, which might not be supported by the provider.

This change does not affect output formatting using Newtonsoft.Json or with XML-based formatters.

Version introduced

ASP.NET Core 6.0

Old behavior

IAsyncEnumerable<T> instances returned from an MVC action as a value to be formatted using ObjectResult or a JsonResult are buffered before being serialized as a synchronous collection.

New behavior

When formatting using System.Text.Json, MVC no longer buffers IAsyncEnumerable<T> instances.

Reason for change

System.Text.Json added support for streaming IAsyncEnumerable<T> types. This allows for a smaller memory footprint during serialization.

If your application requires buffering, consider manually buffering the IAsyncEnumerable<T> object:

// Before
public IActionResult Get()
    return Ok(dbContext.Blogs);

// After
public async Task<IActionResult> Get()
    return Ok(await dbContext.Blogs.ToListAsync());