You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使JsonSerializer.DeserializeAsyncEnumerable异步返回可用部分结果?

问题分析与解决方案

核心问题

你遇到的是.NET中JsonSerializer.DeserializeAsyncEnumerable的回归bug(对应GitHub issue #51702),该bug导致方法在流未完全读取前不会返回任何元素,无法实现预期的JSON流式反序列化——也就是没法在部分结果可用时就异步返回枚举内容。

直接修复:升级.NET版本

这个bug已在特定.NET版本中修复,只需确保项目使用包含该修复的版本即可:

  • .NET 6:升级至6.0.12及以上
  • .NET 7:升级至7.0.1及以上
  • .NET 8及后续版本:默认已集成修复

升级完成后,DeserializeAsyncEnumerable会恢复预期行为:每当流中接收到完整的单个SearchName对象时,就会立即返回该元素,无需等待整个流传输完成。

临时替代方案(无法升级版本时)

如果暂时无法升级.NET版本,可以通过以下两种方式实现流式解析:

方案1:手动处理分块JSON

假设服务器返回的是标准JSON数组格式(如[{}, {}, ...]),可以逐段读取流并识别单个对象的边界,再反序列化单个对象:

using var reader = new StreamReader(outStream);
var buffer = new char[4096];
var jsonFragment = new StringBuilder();
var inArray = false;
var objectDepth = 0;

while (await reader.ReadAsync(buffer, 0, buffer.Length) > 0)
{
    foreach (var c in buffer)
    {
        if (c == '[') inArray = true;
        if (!inArray) continue;

        jsonFragment.Append(c);
        if (c == '{') objectDepth++;
        else if (c == '}') objectDepth--;

        // 当单个对象闭合时,反序列化并重置片段
        if (objectDepth == 0 && c == '}')
        {
            var name = JsonSerializer.Deserialize<SearchName>(jsonFragment.ToString(), opts);
            if (name != null)
            {
                Console.WriteLine(Uri.UnescapeDataString(name.familyName));
            }
            jsonFragment.Clear();
            // 跳过后续的逗号和空格
            while (reader.Peek() is ',' or ' ') reader.Read();
        }
    }
}

方案2:使用第三方流式JSON库

借助Newtonsoft.Json(Json.NET)的JsonTextReader实现原生流式解析,逐个读取并反序列化JSON对象:

using var reader = new JsonTextReader(new StreamReader(outStream));
var serializer = new JsonSerializer();

// 跳过数组起始符号
reader.Read();
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
{
    if (reader.TokenType == JsonToken.StartObject)
    {
        var name = serializer.Deserialize<SearchName>(reader);
        if (name != null)
        {
            Console.WriteLine(Uri.UnescapeDataString(name.familyName));
        }
    }
}

验证流式效果

修复或替换实现后,可以通过以下方式验证是否真正实现流式:

  • 在服务器端用yield return逐个返回SearchName对象
  • 观察客户端控制台是否逐行打印结果,而非等全部数据传输完成后一次性输出

内容的提问来源于stack exchange,提问作者McMurphy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:35:20