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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:27:04