ASP.NET Core 7 Web API禁用IFormFile绑定及流式上传报错解决
解决方案:彻底禁用ASP.NET Core表单绑定并修复流式上传流读取错误
核心问题原因
你遇到的System.IO.IOException: Unexpected end of Stream错误,本质是ASP.NET Core框架会提前自动读取请求流解析表单数据(包括IFormFile),导致后续UploadStream库读取流时,流已被消费完毕。即便移除了表单值提供器工厂,FormFeature仍会被框架自动初始化并读取流,这就是List<IFormFile> Images仍能被绑定的根本原因。
步骤1:彻底禁用表单绑定与流预读取
修改你的DisableFormValueModelBindingAttribute,添加禁用FormFeature自动初始化的逻辑,完全阻止框架提前读取请求流:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter { public void OnResourceExecuting(ResourceExecutingContext context) { // 移除所有表单相关的值提供器工厂 var factories = context.ValueProviderFactories; factories.RemoveType<FormValueProviderFactory>(); factories.RemoveType<FormFileValueProviderFactory>(); factories.RemoveType<JQueryFormValueProviderFactory>(); // 禁用FormFeature自动初始化,避免框架提前读取请求流 context.HttpContext.Features.Set<IFormFeature>(new FormFeature(context.HttpContext.Request, false)); } public void OnResourceExecuted(ResourceExecutedContext context) { } }
步骤2:手动解析Multipart请求填充模型
禁用自动绑定后,需要手动解析Multipart请求的每个Section,区分普通表单字段和文件,手动填充到UploadPresentationCommand模型中:
[HttpPost] [DisableFormValueModelBinding] public async Task<IActionResult> UploadPresentationV1() { byte[] buffer = new byte[1024 * 100]; var model = new UploadPresentationCommand { Images = new List<IFormFile>() }; await this.StreamFiles(async section => { // 处理普通表单字段(无文件名的Section) if (!section.FileName.HasValue) { using var reader = new StreamReader(section.Body); var fieldValue = await reader.ReadToEndAsync(); switch (section.Name) { case nameof(UploadPresentationCommand.Name): model.Name = fieldValue; break; case nameof(UploadPresentationCommand.PresentationContent): model.PresentationContent = fieldValue; break; } return; } // 处理文件流(可根据需求写入磁盘/存储) using (var stream = section.Body) { while (await stream.ReadAsync(buffer, 0, buffer.Length) > 0) { // 处理读取到的字节块 } } // 将文件添加到模型集合 model.Images.Add(new FormFile( section.Body, 0, section.Body.Length, section.Name, section.FileName)); }); // 手动执行模型验证 if (!ModelState.IsValid) { return BadRequest(ModelState); } return Ok("上传完成"); }
关键说明
- 流只能读取一次:Multipart请求流是单向的,一旦被框架或代码读取就无法复用。禁用
FormFeature自动初始化,确保流完全由你的代码控制。 - 区分字段与文件:Multipart请求中,带
FileName的Section是文件,不带的是普通表单字段,需分别处理。 - 手动模型验证:禁用自动绑定后,框架不会自动验证模型,需手动调用
ModelState.IsValid完成验证。
内容的提问来源于stack exchange,提问作者GH_Dev
相关产品推荐
相关产品推荐

