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

无法通过Web Api从Azure Storage向Angular前端返回启用宏的Excel文件

问题解决:从Azure Storage下载带宏的Excel文件时出现“Cannot access a closed Stream.”错误

错误根源

  • API的finally块提前释放了memoryStream,但ASP.NET Core的FileResult需要在后续请求处理阶段读取该流,此时流已关闭导致报错。
  • .xlsm文件的MIME类型使用错误,应使用专属类型而非普通xlsx的类型。
  • 前端responseType配置位置错误,不应放在headers层级。
  • API中硬编码文件名,忽略了传入的参数,不符合设计逻辑。

修正后的API代码(C#)

[HttpGet("download/{fileSource}")]
public async Task<FileResult> DownloadFile([FromRoute] string fileSource)
{
    var storageAccount = CloudStorageAccount.Parse(_storageConnectionString);
    var blobClient = storageAccount.CreateCloudBlobClient();
    var container = blobClient.GetContainerReference("documents");
    var blockBlob = container.GetBlockBlobReference(fileSource);
          
    var memoryStream = new MemoryStream();

    try
    {
        await blockBlob.DownloadToStreamAsync(memoryStream);
        memoryStream.Position = 0;
        // 使用xlsm对应的正确MIME类型
        return File(memoryStream, "application/vnd.ms-excel.sheet.macroEnabled.12", fileSource);
    }
    catch (Exception ex)
    {
        throw;
    }
    // 移除手动Dispose:ASP.NET Core会自动处理FileResult中流的释放
}

修正后的前端代码(Angular)

1. 修正请求选项配置

// responseType需放在请求选项根层级,而非headers内
getDownloadFileHeaderOptions = {
  responseType: 'blob' as 'json' // 类型断言避免TS类型报错
};

2. 修正下载方法

downloadFile(fileSource: string): Observable<Blob> {
  let url = `${environment.APIURL}docs/download/${fileSource}`;
  return this.http.get<Blob>(url, this.getDownloadFileHeaderOptions) 
    .pipe(
      tap(response => {
        // 使用xlsm专属MIME类型创建Blob
        const blob = new Blob([response], { type: 'application/vnd.ms-excel.sheet.macroEnabled.12' });
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = fileSource;
        a.click();
        // 释放URL对象,避免内存泄漏
        window.URL.revokeObjectURL(url);
      })
    );
}

关键说明

  1. 流的释放逻辑:ASP.NET Core的FileResult会在响应发送完成后自动释放流资源,手动在finally块中Dispose会导致流提前关闭。
  2. MIME类型匹配:.xlsm文件必须使用application/vnd.ms-excel.sheet.macroEnabled.12类型,否则可能导致文件无法正常打开或宏丢失。
  3. 前端配置注意:Angular HttpClient的responseType是请求选项的直接属性,放在headers中会被当作普通请求头,无法正确解析响应为Blob。
  4. 内存泄漏处理:下载完成后调用window.URL.revokeObjectURL(url)释放临时URL对象,避免浏览器内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 21:33:31