Clarification on how IAsyncEnumerable works with ASP.NET Web API

Rav*_*tel 12 c# asp.net-core asp.net-core-webapi iasyncenumerable

I encountered an interesting behavior while exploring IAsyncEnumerable in an ASP.NET Web API project. Consider the following code samples:

    // Code Sample 1
    [HttpGet]
    public async IAsyncEnumerable<int> GetAsync()
    {
        for (int i = 0; i < 10; i++)
        {
            await Task.Delay(1000);
            yield return i;
        }
    }


    // Code Sample 2
    [HttpGet]
    public async IAsyncEnumerable<string> GetAsync()
    {
        for (int i = 0; i < 10; i++)
        {
            await Task.Delay(1000);
            yield return i.ToString();
        }
    }
Run Code Online (Sandbox Code Playgroud)

Sample 1 (int array) returns {} as JSON result.

示例 2 返回预期结果["0","1","2","3","4","5","6","7","8","9"]。但是,等待 10 秒后立即返回整个 JSON 数组。当数据按预期从 IAsyncEnumerable 接口可用时,不应该返回它吗?或者有什么特定的方式应该使用这个 web api?

Fab*_*ble 8

在 ASP.NET Core 5 中,实际上IAsyncEnumerable已经通过在内存中缓冲序列并一次性格式化缓冲集合来处理该类型的实例。这解释了为什么您没有收到部分结果。

然而,使用 ASP.NET Core 6.0 这将成为可能

在 ASP.NET Core 6 中,当使用 System.Text.Json 进行格式化时,MVC 不再缓冲 IAsyncEnumerable 实例。相反,MVC 依赖于 System.Text.Json 为这些类型添加的支持(参考

ASP.NET Core 6 计划于 2021 年 11 月发布(参考)。已经可以使用预览版本来测试新行为。我使用预览版 6.0.100-preview.6.21355.2 成功测试了以下代码。该代码生成无限的整数流,并通过控制器返回它IAsyncEnumerable。循环while (true)“证明”数据在处理所有内容之前返回,因为显然循环永远不会终止*。

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace dot_net_api_streaming.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class LoopController : ControllerBase
    {

        [HttpGet]
        public IAsyncEnumerable<int> Get()
        {
            return GetInfiniteInts();
        }

        private async IAsyncEnumerable<int> GetInfiniteInts()
        {
            int index = 0;
            while (true)
                yield return index++;
        }
    }
}
 
Run Code Online (Sandbox Code Playgroud)

*在尝试我的代码时请记住这一点,这样你的机器就不会崩溃:)


tym*_*tam 7

Web api 调用不会每秒返回部分 json。必须等待 10x1 秒的是 json 序列化器(或调用 json 序列化器的代码,它是 ASP .NET 的一部分)。一旦框架代码和序列化器获得所有数据,它将被序列化并作为单个响应提供给客户端。

ASP.NET Core Web API 中的控制器操作返回类型中,我们可以阅读:

在 ASP.NET Core 3.0 及更高版本中,从操作返回 IAsyncEnumerable:

  • 不再导致同步迭代。
  • 变得与返回 IEnumerable 一样高效。

ASP.NET Core 3.0 及更高版本在将以下操作的结果提供给序列化程序之前缓冲它:

public IEnumerable<Product> GetOnSaleProducts() =>
  _context.Products.Where(p => p.IsOnSale);
Run Code Online (Sandbox Code Playgroud)