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

如何在Blazor WASM中实现不预先加载至内存的大文件上传?

解决方案:Blazor WASM流式上传无需服务器分片

你排查得很准确——Blazor WASM的HttpClient.PostAsync在处理StreamContent时,确实会通过ReadAsByteArrayAsync把整个流一次性读取到内存中,这对大文件或大内容上传的性能和内存占用影响很大,而问题根源正是你提到的那段.NET运行时代码。

不用在服务器端引入分片技术的话,直接使用浏览器原生的XMLHttpRequest(XHR)来实现流式上传是最直接的方案,它支持直接发送ReadableStream,不需要预先把整个内容加载到内存里。

实现步骤

  1. 创建Blazor端的C#调用方法
    在你的服务或组件中注入IJSRuntime,然后封装一个调用JS的方法:

    using Microsoft.JSInterop;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;
    
    public class UploadService
    {
        private readonly IJSRuntime _jsRuntime;
    
        public UploadService(IJSRuntime jsRuntime)
        {
            _jsRuntime = jsRuntime;
        }
    
        public async Task<bool> StreamUploadAsync(string uploadUrl, Stream contentStream, string contentType, CancellationToken cancellationToken = default)
        {
            try
            {
                return await _jsRuntime.InvokeAsync<bool>("streamUpload", uploadUrl, contentStream, contentType, cancellationToken);
            }
            catch (JSException ex)
            {
                // 处理JS端抛出的错误
                throw new InvalidOperationException("Upload failed", ex);
            }
        }
    }
    
  2. 添加对应的JavaScript代码
    在你的wwwroot/index.html或者单独的JS文件中添加以下代码:

    window.streamUpload = async function (url, contentStream, contentType, cancellationToken) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.open('POST', url);
            xhr.setRequestHeader('Content-Type', contentType);
    
            // 处理上传取消逻辑
            const abortHandler = () => {
                xhr.abort();
                reject(new Error('Upload was cancelled'));
            };
            cancellationToken.addEventListener('abort', abortHandler);
    
            // 处理上传完成
            xhr.onload = () => {
                cancellationToken.removeEventListener('abort', abortHandler);
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(true);
                } else {
                    reject(new Error(`Upload failed with status code: ${xhr.status}`));
                }
            };
    
            // 处理网络错误
            xhr.onerror = () => {
                cancellationToken.removeEventListener('abort', abortHandler);
                reject(new Error('Network error occurred during upload'));
            };
    
            // 直接发送流,无需预加载到内存
            xhr.send(contentStream);
        });
    };
    

关键优势

  • 真正的流式上传:利用浏览器原生API直接发送流,不会把整个内容加载到内存,完美解决内存占用问题。
  • 无需服务器改动:服务器只需要处理常规的POST请求体即可,不需要额外的分片接收逻辑。
  • 支持取消和错误处理:集成了CancellationToken来处理上传取消,同时覆盖了网络错误和HTTP状态码错误场景。

可选扩展

如果需要跟踪上传进度,可以在JS代码中添加xhr.upload.onprogress事件监听:

xhr.upload.onprogress = (event) => {
    if (event.lengthComputable) {
        const progress = (event.loaded / event.total) * 100;
        console.log(`Upload progress: ${progress.toFixed(2)}%`);
        // 这里可以通过JS互操作把进度传回Blazor端
    }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 18:03:10