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

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("上传完成");
}

关键说明

  1. 流只能读取一次:Multipart请求流是单向的,一旦被框架或代码读取就无法复用。禁用FormFeature自动初始化,确保流完全由你的代码控制。
  2. 区分字段与文件:Multipart请求中,带FileName的Section是文件,不带的是普通表单字段,需分别处理。
  3. 手动模型验证:禁用自动绑定后,框架不会自动验证模型,需手动调用ModelState.IsValid完成验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:05:17