簡體   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