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

.NET 6 Web API中如何修改文件上传进度事件?

解决方案:自定义文件上传进度(无需额外接口)

默认情况下,ASP.NET Core的[FromForm]模型绑定会在进入控制器方法前完成整个请求体(包括文件)的接收,所以前端看到的100%进度只是文件上传到服务器的进度,而非后端业务处理的进度。要实现你要的效果,需要绕开默认绑定,手动处理请求流并通过**分块传输编码(Chunked Transfer Encoding)**向前端实时推送进度。

后端(.NET 6 Web API)实现步骤

  1. 移除[FromForm],手动解析Multipart请求
  2. 接收文件后推送中间进度(比如60%)
  3. 执行文件保存逻辑后推送100%进度
  4. 返回最终响应

控制器代码示例

using Microsoft.AspNetCore.WebUtilities;
using System.IO;
using System.Text;

[HttpPost("upload")]
public async Task<IActionResult> Upload()
{
    if (!Request.HasFormContentType)
    {
        return BadRequest("无效的请求内容类型");
    }

    var boundary = MultipartRequestHelper.GetBoundary(
        MediaTypeHeaderValue.Parse(Request.ContentType),
        defaultMultipartBoundaryLength: 100);
    var reader = new MultipartReader(boundary, Request.Body);
    var section = await reader.ReadNextSectionAsync();

    // 遍历表单字段,定位到上传的文件
    while (section != null)
    {
        var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
        if (hasContentDispositionHeader && contentDisposition.IsFileDisposition())
        {
            // 1. 文件已上传至服务器,推送60%进度
            await SendProgressAsync(60);

            // 2. 执行文件保存逻辑
            using var stream = new MemoryStream();
            await section.Body.CopyToAsync(stream);
            stream.Position = 0;
            await _fileService.SaveAsync(stream, contentDisposition.FileName.Value);

            // 3. 保存完成,推送100%进度
            await SendProgressAsync(100);

            return Ok(new { message = "文件上传完成" });
        }

        section = await reader.ReadNextSectionAsync();
    }

    return BadRequest("未找到上传的文件");
}

private async Task SendProgressAsync(int percentage)
{
    // 设置响应头:启用分块传输,避免后端缓冲整个响应
    Response.Headers.TransferEncodingChunked = "true";
    Response.ContentType = "text/plain";

    // 发送进度数据(添加换行符,方便前端逐行解析)
    var progressData = $"progress:{percentage}\n";
    await Response.Body.WriteAsync(Encoding.UTF8.GetBytes(progressData));
    await Response.Body.FlushAsync();
}

前端(Angular)实现步骤

前端需要监听服务器的分块响应(对应HTTP的下载进度事件),解析每个分块中的进度信息,更新UI进度条。

Angular代码示例

uploadFile(file: File): void {
  const formData = new FormData();
  formData.append('file', file);
  this.uploadProgress = 0;

  this.http.post('/api/upload', formData, {
    reportProgress: true,
    observe: 'events',
    responseType: 'text'
  }).subscribe({
    next: (event) => {
      if (event.type === HttpEventType.DownloadProgress) {
        // 解析分块返回的进度文本
        const progressText = event.partialText ?? '';
        const progressMatch = progressText.match(/progress:(\d+)/);
        if (progressMatch) {
          const percentage = parseInt(progressMatch[1], 10);
          this.uploadProgress = percentage;
        }
      } else if (event.type === HttpEventType.Response) {
        // 上传完成,处理最终响应
        console.log(event.body);
      }
    },
    error: (err) => {
      console.error('上传失败', err);
    }
  });
}

关键说明

  • 分块传输:ASP.NET Core会自动处理分块响应,调用FlushAsync可立即将进度数据推送到客户端,无需手动拆分数据块。
  • 进度格式:示例中用progress:XX的简单格式,你也可以自定义为JSON格式(比如{"progress":60}),只需同步修改前后端的解析逻辑。
  • 资源清理:手动处理请求流时,务必使用using语句释放资源,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 13:50:41