Blazor Server+ASP.NET Core多文件上传功能异常问题排查
问题背景
前后端分离项目,前端基于Blazor Server开发,后端为ASP.NET Core,文件上传功能出现异常:前端打印Check-3日志后触发请求发送错误,后端未接收到请求;多文件上传时还会出现文件ID不存在的错误。项目其他接口运行正常,已验证请求URL与后端端点匹配。
前端文件上传服务代码
public async Task<IEnumerable<FileMetaDataDto>> UploadFileAsync(IList<IBrowserFile> files, Guid projectId, Guid? commentId) { using var content = new MultipartFormDataContent(); foreach (var file in files) { var fileContent = new StreamContent(file.OpenReadStream()); fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "files", FileName = file.Name, }; fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType); content.Add(fileContent); } Console.WriteLine($"Check-3 {projectId}, Comment ID: {commentId}, Content: {content}"); var response = await _httpClient.PostAsync($"api/Files/project/{projectId}/upload-multiple?commentId={commentId}", content); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync<IEnumerable<FileMetaDataDto>>(); }
后端ASP.NET Core控制器代码
[HttpPost("project/{projectId}/upload-multiple")] public async Task<IActionResult> UploadMultiple(IEnumerable<IFormFile> files, Guid projectId, [FromQuery] Guid? commentId) { Console.WriteLine("Check server side"); var results = await _fileService.UploadMultipleFilesAsync(files, projectId, commentId); return Ok(results); }
错误信息
- 单/多文件上传时,前端打印
Check-3后报错:
An error occurred while sending the request.
后端未打印Check server side日志。
- 多文件上传时额外触发错误:
Error: There is no file with ID 1. The file list may have changed.
Error: There is no file with ID 1. The file list may have changed.
at Ze (https://localhost:55327/_framework/blazor.server.js:1:36968)
at Object.readFileData (https://localhost:55327/_framework/blazor.server.js:1:36894)
at https://localhost:55327/_framework/blazor.server.js:1:3244
at new Promise ()
at y.beginInvokeJSFromDotNet (https://localhost:55327/_framework/blazor.server.js:1:3201)
at Yt._invokeClientMethod (https://localhost:55327/_framework/blazor.server.js:1:60713)
at Yt._processIncomingData (https://localhost:55327/_framework/blazor.server.js:1:58188)
at Yt.connection.onreceive (https://localhost:55327/_framework/blazor.server.js:1:51829)
at s.onmessage (https://localhost:55327/_framework/blazor.server.js:1:79974)
后端文件服务多文件上传代码
public async Task<List<FileMetadataDto>> UploadMultipleFilesAsync(IEnumerable<IFormFile> files, Guid projectId, Guid? commentId) { var responses = new List<FileMetadataDto>(); foreach (var file in files) { FileMetadataDto response = await UploadFileAsync(file, projectId, commentId); responses.Add(response); } return responses; }
解决方案
1. 修复文件ID不存在错误
Blazor Server中<InputFile>的文件对象绑定客户端状态,异步操作后复用IBrowserFile会导致客户端文件资源释放,触发ID不存在错误。修改前端代码,立即将文件流读取到内存流:
public async Task<IEnumerable<FileMetaDataDto>> UploadFileAsync(IList<IBrowserFile> files, Guid projectId, Guid? commentId) { using var content = new MultipartFormDataContent(); foreach (var file in files) { // 立即读取文件到内存流,避免客户端资源释放 using var memoryStream = new MemoryStream(); await file.OpenReadStream().CopyToAsync(memoryStream); memoryStream.Position = 0; var fileContent = new StreamContent(memoryStream); fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "files", FileName = file.Name, }; fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType); content.Add(fileContent); } Console.WriteLine($"Check-3 {projectId}, Comment ID: {commentId}, Content: {content}"); var response = await _httpClient.PostAsync($"api/Files/project/{projectId}/upload-multiple?commentId={commentId}", content); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync<IEnumerable<FileMetaDataDto>>(); }
2. 排查请求发送失败问题
若修改后仍无法发送请求,检查以下项:
- 确认
_httpClient的BaseAddress配置正确,跨域规则(若前后端域名不同)已配置。 - 后端添加文件大小限制配置(在
Program.cs中):
builder.Services.Configure<FormOptions>(options => { options.MultipartBodyLengthLimit = 10 * 1024 * 1024; // 按需调整大小,示例为10MB });
- 捕获详细异常信息,替换
response.EnsureSuccessStatusCode()为:
try { var response = await _httpClient.PostAsync($"api/Files/project/{projectId}/upload-multiple?commentId={commentId}", content); if (!response.IsSuccessStatusCode) { var errorMsg = await response.Content.ReadAsStringAsync(); Console.WriteLine($"Request failed: {response.StatusCode}, Details: {errorMsg}"); throw new HttpRequestException($"Upload failed: {errorMsg}"); } } catch (Exception ex) { Console.WriteLine($"Request error: {ex.Message}, Inner: {ex.InnerException?.Message}"); throw; }
3. 确保后端参数绑定正常
给后端控制器的files参数添加[FromForm]标记,明确绑定来源:
public async Task<IActionResult> UploadMultiple([FromForm] IEnumerable<IFormFile> files, Guid projectId, [FromQuery] Guid? commentId)
内容的提问来源于stack exchange,提问作者Mr Dot

