Blazor WASM文件下载API报错:该流不支持超时
解决Azure Blob流式传输时的"Timeouts are not supported on this stream"错误
问题原因
当你在Minimal API中返回Results.Ok(Stream)时,ASP.NET Core会尝试将Stream对象序列化为JSON。但Azure Blob Storage的OpenReadAsync返回的Stream实现不支持ReadTimeout属性,Json序列化器在反射访问该属性时触发了InvalidOperationException。
修复方案
正确的做法是直接将Blob流写入HTTP响应体,而非让框架序列化Stream对象。同时需要设置必要的响应头,确保客户端能正确处理文件下载。
1. 扩展BlobService以返回元数据
修改BlobService,返回包含流、Content-Type和文件名的结果对象,方便API设置响应头:
public class BlobStreamResult { public Stream Stream { get; init; } public string ContentType { get; init; } public string FileName { get; init; } } public class BlobService : IBlobService { readonly BlobServiceClient _svcClient; BlobContainerClient GetContainerClient(string containerName) => _svcClient.GetBlobContainerClient(containerName); BlobClient GetBlobClient(string containerName, string file) => GetContainerClient(containerName).GetBlobClient(file); public BlobService(string blobEndpoint) { var cred = new DefaultAzureCredential(); _svcClient = new BlobServiceClient(new Uri(blobEndpoint), cred); } public async Task<BlobStreamResult> GetBlobStreamWithMetadata(string containerName, string file) { var blobClient = GetBlobClient(containerName, file); var propertiesResponse = await blobClient.GetPropertiesAsync(); var stream = await blobClient.OpenReadAsync(); return new BlobStreamResult { Stream = stream, ContentType = propertiesResponse.Value.ContentType, FileName = file }; } }
2. 修改API端点直接流式传输
调整Minimal API端点代码,直接操作HttpContext.Response写入流并设置响应头:
app.MapGet("/download/{container}/{blob}", async (HttpContext ctx, IBlobService blobSvc, string container, string blob) => { var blobResult = await blobSvc.GetBlobStreamWithMetadata(container, blob); // 设置响应头,指定文件类型和下载行为 ctx.Response.ContentType = blobResult.ContentType; ctx.Response.Headers.ContentDisposition = $"attachment; filename=\"{blobResult.FileName}\""; // 将Blob流复制到响应体,流式传输 await using (blobResult.Stream) { await blobResult.Stream.CopyToAsync(ctx.Response.Body); await ctx.Response.Body.FlushAsync(); } return Results.Ok(); }) .RequireAuthorization(AuthzPolicy.Policy);
3. 客户端代码无需修改
Blazor WASM的下载代码和JS互操作逻辑保持不变即可,PowerShell的iwr命令也能正确处理流式响应,不会再触发序列化错误。
关键说明
- 直接流式传输避免了将整个Blob加载到内存,完全符合你降低API内存消耗的需求。
Content-Disposition头会让浏览器自动识别为下载文件,提升用户体验。- 使用
await using确保Blob流被正确释放,避免资源泄漏。
内容的提问来源于stack exchange,提问作者baouss
相关产品推荐
相关产品推荐

