繁体   English   中英

说明 IAsyncEnumerable 如何与 ASP.NET Web API 一起使用

[英]Clarification on how IAsyncEnumerable works with ASP.NET Web API

在 ASP.NET Web API 项目中探索 IAsyncEnumerable 时,我遇到了一个有趣的行为。 考虑以下代码示例:

    // 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();
        }
    }

示例 1(int 数组)返回{}作为 JSON 结果。

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

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

Controller 动作返回类型中 ASP.NET 核心 web ZDB974238714CA8DE634A7CE1D083A14我们可以阅读:

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

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

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

public IEnumerable<Product> GetOnSaleProducts() =>
  _context.Products.Where(p => p.IsOnSale);

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

然而,使用 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 成功测试了以下代码。 该代码产生一个无限的整数 stream 并使用IAsyncEnumerable通过 controller 返回它。 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++;
        }
    }
}
 

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM