C# Blazor从流下载文件 C# Blazor Server/WASM如何生成并下载文件

来源:这里教程网 时间:2026-02-21 17:43:06 作者:

Blazor Server 中用
FileStreamResult
FileContentResult
会失败

Blazor Server 是服务端渲染,但 HTTP 响应已由 SignalR 连接接管,直接返回

FileStreamResult
或调用
Response.Body.WriteAsync
不生效——浏览器收不到文件头,下载不会触发。你看到的可能是空白页、控制台报错
Failed to launch download: no file
,或完全静默。

正确做法是:在后端提供一个标准 MVC/Controller 接口(非组件内方法),生成文件并返回

FileContentResult
PhysicalFileResult
,再从 Blazor 组件中用 JS 启动下载。

新建一个
Controllers/DownloadController.cs
,添加
[HttpGet("api/download/{id}")]
方法
文件内容建议先写入
MemoryStream
,再转为
byte[]
,避免流生命周期问题
设置
ContentType
(如
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)和
FileDownloadName
前端用
NavigationManager.NavigateTo("/api/download/123", forceLoad: true)
会刷新页面;更推荐用 JS interop 触发
window.location.href
fetch
+
URL.createObjectURL

Blazor WASM 中无法直接访问服务器文件系统

WASM 运行在浏览器沙箱里,

System.IO.File
只能读取嵌入资源或通过
IJSRuntime
拿到的用户选择文件。想“生成并下载”,所有逻辑必须在客户端完成。

典型场景:导出 CSV、生成 PDF(用

jsPDF
)、导出 Excel(用
SheetJS
)。关键点是别试图在 C# 里写文件到磁盘——没意义,也做不到。

MemoryStream
构造数据(如 CSV 字符串转
Encoding.UTF8.GetBytes()
调用 JS interop:
await JS.InvokeVoidAsync("downloadFile", fileName, base64String)
JS 端用
Uint8Array
Blob
URL.createObjectURL
a.download
触发保存
注意:WASM 下
Encoding.UTF8.GetBytes()
中文不乱码,但若用
Encoding.Default
可能出错

JS.InvokeVoidAsync("downloadFile", ...)
的 JS 实现要处理 Blob 兼容性

常见错误是只用

data:text/csv;base64,...
链接,Safari 不支持长 URL,Edge 旧版可能截断。稳妥方式是走 Blob +
createObjectURL

wwwroot/js/site.js
里定义:

function downloadFile(fileName, base64String) {
    const byteString = atob(base64String);
    const len = byteString.length;
    const bytes = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
        bytes[i] = byteString.charCodeAt(i);
    }
    const blob = new Blob([bytes], { type: 'application/octet-stream' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = fileName;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
}
不要省略
URL.revokeObjectURL
,否则内存泄漏
如果文件类型明确(如 PDF),把
type
改成
"application/pdf"
,有助于浏览器识别
IE11 不支持
Blob
构造函数传
Uint8Array
,需降级用
new Blob([bytes.buffer])

大文件下载时内存和超时要单独处理

生成 100MB Excel 或 ZIP 时,

MemoryStream
会吃光 WASM 堆内存(默认 128MB),Server 端则可能触发 Kestrel 请求超时或 IIS 上传限制。

WASM:改用分块生成 + 流式下载不可行;实际应避免前端生成大文件,改由后端异步生成、返回下载链接(带 token 防盗链) Server:Controller 接口里别用
FileContentResult
加载整个文件到内存;改用
FileStreamResult
包裹
FileStream
(注意
FileShare.Read
和异步
CopyToAsync
无论哪种模式,都应在响应头加
Content-Disposition: attachment; filename="xxx"
,且确保 Controller 方法不被
[ValidateAntiForgeryToken]
拦截

最易被忽略的是:Blazor Server 的 SignalR 连接默认 5 分钟超时,而大文件生成可能耗时更久——得同时调大

HubOptions.KeepAliveInterval
和客户端重连逻辑。

相关推荐

热文推荐