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

Blazor Server调用Web API获取流文件时遇已关闭流异常求助

解决Blazor Server调用WebAPI下载文件时的流已关闭异常

错误原因

你遇到的System.ObjectDisposedException核心原因是Blazor端未等待JavaScript异步操作完成就提前释放了流资源:

  • JS.InvokeVoidAsync是异步方法,但你未使用await等待它执行完毕,导致using var streamRef在代码块结束时立即释放了DotNetStreamReference及关联的文件流;
  • 此时JavaScript端仍在尝试读取流内容,因此触发"无法访问已关闭的流"的异常。

此外,HttpClient.GetAsync默认会将整个响应缓冲到内存,直接读取流也存在潜在的生命周期管理问题。

修复方案

1. 修正Blazor端的异步调用与流生命周期

修改DownLoadFile方法,确保等待JavaScript操作完成后再释放流:

private async Task DownLoadFile()
{
    serviceEndpoint = $"{Config.GetValue<string>("WAPIUrl")}ExportEmployeesCsv2/";
    // 使用ResponseHeadersRead避免缓冲整个响应,直接读取流(适合大文件场景)
    var result = await httpClient.GetAsync(serviceEndpoint, HttpCompletionOption.ResponseHeadersRead);
    
    if (!result.IsSuccessStatusCode) 
    {
        await JS.InvokeVoidAsync("Alert", "not found");
    }
    else
    {
        // 用using包裹流,确保操作完成后自动释放资源
        using var fileStream = await result.Content.ReadAsStreamAsync();
        using var streamRef = new DotNetStreamReference(stream: fileStream);
        
        // 必须await JS调用,确保流在读取完成后再被释放
        await JS.InvokeVoidAsync("downloadFileFromStream", "test.csv", streamRef);
    }          
}

2. 优化WebAPI端代码(可选,提升性能)

原WebAPI代码手动将文件读入内存流,可简化为直接返回物理文件,让ASP.NET Core自动处理流的生命周期,减少内存占用:

[HttpGet("ExportEmployeesCsv2")]
public IActionResult ExportEmployeesCsv()
{
    var path = Path.Combine(Directory.GetCurrentDirectory(), "tmp", "test.csv");
    // 直接返回物理文件,无需手动处理内存流
    return PhysicalFile(path, "text/csv", Path.GetFileName(path));
}

关键说明

  • 必须await JS.InvokeVoidAsync:JavaScript的文件读取是异步操作,只有等待其完成后,才能安全释放关联的.NET流资源;
  • 使用HttpCompletionOption.ResponseHeadersRead:对于大文件下载,该选项可避免将整个文件加载到内存,提升应用性能和稳定性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 11:18:19