.NET 8独立进程Azure Functions返回IAsyncEnumerable报错求助
在使用.NET 8独立进程的Azure Functions HttpTrigger时,尝试返回IAsyncEnumerable<MyObject>类型,遇到如下错误:
'.IAsyncEnumerable' can only be serialized using async serialization methods.
at System.Text.Json.ThrowHelper.ThrowNotSupportedException_TypeRequiresAsyncSerialization(Type propertyType)
at System.Text.Json.Serialization.Converters.IAsyncEnumerableOfTConverter2.OnTryWrite(Utf8JsonWriter writer, TAsyncEnumerable value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter1.TryWrite(Utf8JsonWriter writer, T& value, etc.
——更新——
深入查找后在learn.microsoft.com找到相关问题,指向GitHub上关于gRPC代理层需先序列化完整内容再发送给客户端的issue,该issue评论提到Azure Functions现已支持ASP.NET Core集成预览版,本应解决此问题,但文档中无流式处理示例。此前在.NET6进程内模式V2兼容模式下,可返回带PushStreamContent的HttpResponseMessage实现流式处理,当前情况感觉是一种倒退。
解决方案
方法1:启用ASP.NET Core集成预览版(推荐)
Azure Functions的ASP.NET Core集成预览版原生支持流式响应,可解决独立进程模式下的序列化限制:
- 在项目文件(.csproj)中添加配置:
<PropertyGroup> <FunctionsWorkerRuntime>dotnet-isolated</FunctionsWorkerRuntime> <EnableAspNetCoreIntegration>true</EnableAspNetCoreIntegration> </PropertyGroup>
- 更新
Program.cs,配置ASP.NET Core请求处理管道:
var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults(worker => { worker.UseAspNetCoreIntegration(); }) .Build(); host.Run();
- 在HttpTrigger函数中直接返回
IAsyncEnumerable<MyObject>:
[Function("StreamData")] public IAsyncEnumerable<MyObject> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest req) { return GenerateDataAsync(); } private async IAsyncEnumerable<MyObject> GenerateDataAsync() { for (int i = 0; i < 10; i++) { await Task.Delay(100); yield return new MyObject { Id = i, Name = $"Item {i}" }; } }
方法2:手动控制响应流(兼容现有独立进程模式)
如果暂时无法启用预览版,可通过直接操作HttpResponseData手动异步序列化IAsyncEnumerable,模拟PushStreamContent的行为:
[Function("StreamData")] public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest req, HttpResponseData res) { res.Headers.Add("Content-Type", "application/json"); await using var writer = new Utf8JsonWriter(res.Body); writer.WriteStartArray(); await foreach (var item in GenerateDataAsync()) { JsonSerializer.Serialize(writer, item); } writer.WriteEndArray(); await writer.FlushAsync(); }
这种方式绕过Functions默认的序列化逻辑,直接将流式数据写入响应体。
方法3:回退到进程内模式(临时方案)
如果上述方法都无法满足需求,可暂时回退到.NET 6/8的进程内模式(非独立进程),继续使用PushStreamContent实现流式处理,但会失去独立进程模式的隔离性优势。
内容的提问来源于stack exchange,提问作者Lenny D

