Razor Pages多文件上传报错:Cannot access a disposed object. FileBufferingReadStream
问题分析与解决方案
问题原因
这个错误是因为IFormFile对应的FileBufferingReadStream流与HTTP请求上下文绑定,请求处理完成后流会被自动释放。当你通过MediatR异步调用InsertDocumentsAsync时,可能请求已经结束、流已被销毁,此时再尝试读取第二个文件的流就会触发“无法访问已释放对象”的报错。另外,如果在处理第一个文件时错误手动释放了流,或是流的作用域设置不当,也会导致后续文件无法读取。
解决方法
核心思路是提前将文件内容从请求绑定的流中读取出来,脱离请求上下文的依赖,再传递给后续处理逻辑,具体步骤如下:
1. 修改DTO结构,存储文件内容而非IFormFile
创建包含文件元数据和内容的新DTO,替代直接传递IFormFile对象:
public class ProcessedDocumentDTO { public string FileName { get; set; } public string ContentType { get; set; } public byte[] Content { get; set; } }
2. 在Razor Page的Post处理程序中提前读取文件内容
在请求生命周期内,把每个上传文件的内容读取到内存数组中,再传递给MediatR命令:
public async Task<IActionResult> OnPostFileUploadAsync(List<ApplicationDocumentDTO> incomingDocuments) { var processedDocs = new List<ProcessedDocumentDTO>(); foreach (var doc in incomingDocuments) { using var ms = new MemoryStream(); await doc.SupportingDocument.CopyToAsync(ms); processedDocs.Add(new ProcessedDocumentDTO { FileName = doc.SupportingDocument.FileName, ContentType = doc.SupportingDocument.ContentType, Content = ms.ToArray() }); } // 调用MediatR命令传递处理后的文件数据 await _mediator.Send(new InsertDocumentsCommand(processedDocs)); return RedirectToPage(); }
3. 调整仓储处理逻辑
在InsertDocumentsAsync中直接使用ProcessedDocumentDTO的Content属性(字节数组)写入数据库,无需再操作IFormFile的流:
public async Task InsertDocumentsAsync(List<ProcessedDocumentDTO> documents) { foreach (var doc in documents) { var dbDoc = new ApplicationDocument { FileName = doc.FileName, ContentType = doc.ContentType, Content = doc.Content }; _dbContext.ApplicationDocuments.Add(dbDoc); } await _dbContext.SaveChangesAsync(); }
额外检查点
- 不要手动调用
IFormFile.Dispose(),ASP.NET会自动管理IFormFile的生命周期,手动释放会导致后续文件流失效。 - 确认MediatR命令处理程序中没有延迟异步操作,避免请求上下文提前结束。
内容的提问来源于stack exchange,提问作者Dibakar
相关产品推荐
相关产品推荐

