Blazor对接ASP.NET WebAPI时如何跟踪HttpClient.PostAsync上传进度
解决方案
你不需要修改现有注入的HttpClient配置,只需要实现一个轻量的带进度上报的StreamContent子类,修改几行原有代码即可,实现逻辑非常容易理解:
第一步:实现自定义带进度的StreamContent
public class ProgressableStreamContent : StreamContent { private readonly Stream _contentStream; private readonly Action<long, long> _progressCallback; private readonly long _totalLength; public ProgressableStreamContent(Stream stream, long totalLength, Action<long, long> progressCallback) : base(stream) { _contentStream = stream; _totalLength = totalLength; _progressCallback = progressCallback; } protected override async Task SerializeToStreamAsync(Stream stream, System.Net.TransportContext context) { var buffer = new byte[4096]; long uploadedBytes = 0; int readBytes; while ((readBytes = await _contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await stream.WriteAsync(buffer, 0, readBytes); uploadedBytes += readBytes; _progressCallback?.Invoke(uploadedBytes, _totalLength); } } }
该类仅重写了流序列化到请求的核心方法,每次读取文件流写入请求流时累计已上传字节数,向上层回调进度数据。
第二步:修改你的UploadFiles方法
public async Task<bool> UploadFiles(Action<int> callback, IReadOnlyList<IBrowserFile> files, string subdir = "") { if (files == null || !files.Any()) return false; hasItemsForUpload = true; // 计算所有上传文件总大小,用于统计整体进度百分比 long totalSize = files.Sum(f => f.Size); long totalUploaded = 0; // 去重重复的进度回调,减少无效UI更新 int lastReportedProgress = 0; var content = new MultipartFormDataContent(); foreach (var file in files) { var fileStream = file.OpenReadStream(_allowedMaxFileSize); // 传入单文件大小和进度回调逻辑 var fileContent = new ProgressableStreamContent(fileStream, file.Size, (uploaded, total) => { // 线程安全累加已上传总字节数 Interlocked.Add(ref totalUploaded, uploaded); int progress = (int)Math.Round((double)totalUploaded / totalSize * 100); // 仅百分比发生变化时触发回调 if (progress > lastReportedProgress && progress <= 100) { lastReportedProgress = progress; callback(progress); } }); content.Add(fileContent, "\"files\"", file.Name); } var uri = $"api/mycontroller/upload?subdir={subdir}"; var result = await _http.PostAsync(uri, content); if (result.IsSuccessStatusCode) { // 确保100%进度回调 if (lastReportedProgress < 100) callback(100); return true; } return false; }
相关说明
- 该实现完全不影响你现有依赖注入的
HttpClient实例,不需要修改Startup/Program文件中的服务注册逻辑 - 示例默认统计多文件整体上传进度,如需单个文件的独立进度,仅需调整回调逻辑即可
- 4096的缓冲区大小可根据需求调整:缓冲区越大上传效率越高、进度更新粒度越粗,反之进度更新更细腻
内容的提问来源于stack exchange,提问作者GAC
相关产品推荐
相关产品推荐

