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

ASP.NET Core 6中如何控制IAsyncEnumerable<string>的响应格式化?

实现ASP.NET Core流式返回每行JSON格式的字符串

方案1:自定义TextOutputFormatter(推荐,符合框架设计)

创建自定义格式化器,支持异步枚举的流式输出,确保每行输出JSON格式的字符串:

using Microsoft.AspNetCore.Mvc.Formatters;
using System.Text.Json;

public class LineDelimitedJsonStringFormatter : TextOutputFormatter
{
    public LineDelimitedJsonStringFormatter()
    {
        // 设置支持的媒体类型,可按需调整
        SupportedMediaTypes.Add("text/plain");
        SupportedMediaTypes.Add("application/x-json-lines");

        // 配置支持的编码格式
        SupportedEncodings.Add(System.Text.Encoding.UTF8);
        SupportedEncodings.Add(System.Text.Encoding.Unicode);
    }

    protected override bool CanWriteType(Type? type)
    {
        // 仅处理返回IAsyncEnumerable<string>的Action
        return type != null && typeof(IAsyncEnumerable<string>).IsAssignableFrom(type);
    }

    public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
    {
        if (context.Object is not IAsyncEnumerable<string> asyncEnumerable)
            return;

        var response = context.HttpContext.Response;
        await using var writer = new StreamWriter(response.Body, selectedEncoding);
        var jsonOptions = new JsonSerializerOptions();

        // 异步枚举序列,逐个输出JSON格式字符串+换行
        await foreach (var item in asyncEnumerable)
        {
            var jsonString = JsonSerializer.Serialize(item, jsonOptions);
            await writer.WriteLineAsync(jsonString);
            // 立即刷新流,确保数据实时发送到客户端
            await writer.FlushAsync();
        }
    }
}

在Program.cs中注册该格式化器:

builder.Services.AddControllers(options =>
{
    // 将自定义格式化器插入到最前面,优先匹配
    options.OutputFormatters.Insert(0, new LineDelimitedJsonStringFormatter());
});

控制器Action中指定返回媒体类型:

[HttpGet]
[Produces("text/plain")]
public async IAsyncEnumerable<string> GetAsync()
{
    for (var i = 0; i < 3; i++)
    {
        yield return i.ToString();
        // 模拟异步读取文件等操作
        await Task.Delay(100);
    }
}

方案2:直接操作Response(简单场景快速实现)

若无需复用格式化逻辑,可直接在控制器中写入响应流:

using System.Text.Json;

[HttpGet]
public async Task GetAsync()
{
    var response = HttpContext.Response;
    response.ContentType = "text/plain";
    
    await using var writer = new StreamWriter(response.Body);
    var jsonOptions = new JsonSerializerOptions();

    for (var i = 0; i < 3; i++)
    {
        var item = i.ToString();
        // 将单个字符串序列化为带引号的JSON格式
        var jsonString = JsonSerializer.Serialize(item, jsonOptions);
        await writer.WriteLineAsync(jsonString);
        // 刷新流确保数据实时推送
        await writer.FlushAsync();
        
        await Task.Delay(100); // 模拟异步操作
    }
}

关键说明

  • 手动添加Environment.NewLine无效的原因:默认JSON格式化器会将整个IAsyncEnumerable<string>序列化为单行JSON数组,所有特殊字符(包括换行)都会被转义,无法实现逐行输出。
  • 流式输出的保证:两种方案均通过await foreach或逐次写入后刷新流,确保数据逐个发送到客户端,不会等待整个序列枚举完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 08:45:49