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
相关产品推荐
相关产品推荐

