.NET 6 Web API中如何修改文件上传进度事件?
解决方案:自定义文件上传进度(无需额外接口)
默认情况下,ASP.NET Core的[FromForm]模型绑定会在进入控制器方法前完成整个请求体(包括文件)的接收,所以前端看到的100%进度只是文件上传到服务器的进度,而非后端业务处理的进度。要实现你要的效果,需要绕开默认绑定,手动处理请求流并通过**分块传输编码(Chunked Transfer Encoding)**向前端实时推送进度。
后端(.NET 6 Web API)实现步骤
- 移除
[FromForm],手动解析Multipart请求 - 接收文件后推送中间进度(比如60%)
- 执行文件保存逻辑后推送100%进度
- 返回最终响应
控制器代码示例
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
相关产品推荐
相关产品推荐

