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

C#控制器API实现带Swagger文档的多部分文件上传问题

C# Web API多部分文件上传的Swagger文档生成解决方案

问题背景

需要实现符合Swagger规范的多部分文件上传API,并生成正确的Swagger文档,尝试两种方式均未达到预期:

方式1:手动读取Request表单

通过Request.ReadFormAsync读取文件和JSON字符串,但Swashbuckle无法自动识别请求结构,生成的Swagger缺失requestBody部分,不符合预期格式。

代码示例:

public async Task<IActionResult> Upload()
{
    var form = await Request.ReadFormAsync();
    var file = form.Files.FirstOrDefault();
    var jsonString = form["json"].ToString();
    // ...业务逻辑
}

自动生成的Swagger(缺失requestBody):

openapi: 3.0.0
info:
  title: Example
  version: 1.0.0
paths:
  /upload:
    post:
      summary: Uploads data
      responses:
        '200':
          description: OK

方式2:IFormFile + [FromForm]模型

使用IFormFile单独接收文件,搭配[FromForm]修饰的Document模型接收表单数据,但Swashbuckle.AspNetCore 6.5.0生成的文档不符合预期结构。

代码示例:

public class Document
{
    public string CompanyId { get; set; }
    public DocumentType Type { get; set; }
    public string Description { get; set; }
}

public async Task<IActionResult> Upload(IFormFile file, [FromForm] Document model)
{
    // ...业务逻辑
}

解决方案

方案1:强类型模型整合(推荐)

将IFormFile字段直接整合到表单模型中,使用单个[FromForm]修饰的模型参数,让Swashbuckle自动识别完整的multipart请求结构。

1. 调整模型定义

将文件字段加入Document模型,支持嵌套复杂类型:

public class Document
{
    public string CompanyId { get; set; }
    public DocumentType Type { get; set; }
    public string Description { get; set; }
    // 对应上传的文件字段
    public IFormFile ProfileImage { get; set; }
    // 嵌套对象示例(匹配预期中的address结构)
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
}

2. 调整控制器方法

使用单个[FromForm]修饰的模型参数统一接收表单数据和文件:

[HttpPost("upload")]
public async Task<IActionResult> Upload([FromForm] Document model)
{
    // 读取上传的文件
    var uploadedFile = model.ProfileImage;
    // 读取表单字段
    var companyId = model.CompanyId;
    var userAddress = model.Address;
    // ...业务逻辑
}

3. Swagger配置优化

确保Swashbuckle正确解析嵌套类型,在Program.cs(或Startup.cs)中添加配置:

builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Example", Version = "v1" });
    // 启用扩展引用Schema,保证嵌套类型正确生成文档
    c.UseAllOfToExtendReferenceSchemas();
});

此方案生成的Swagger文档会自动包含完整的multipart/form-data请求体结构,与预期格式完全匹配。

方案2:手动添加Swagger描述(针对方式1)

若坚持使用Request.ReadFormAsync手动读取表单,需通过自定义操作过滤器手动补全Swagger的requestBody描述。

1. 创建自定义操作过滤器

public class MultipartFormDataOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        // 仅对目标接口生效
        if (context.ApiDescription.HttpMethod != HttpMethod.Post.Method 
            || context.ActionDescriptor.RouteValues["action"] != "Upload")
            return;

        operation.RequestBody = new OpenApiRequestBody
        {
            Required = true,
            Content = new Dictionary<string, OpenApiMediaType>
            {
                ["multipart/form-data"] = new OpenApiMediaType
                {
                    Schema = new OpenApiSchema
                    {
                        Type = "object",
                        Properties = new Dictionary<string, OpenApiSchema>
                        {
                            ["json"] = new OpenApiSchema { Type = "string" },
                            ["profileImage"] = new OpenApiSchema { Type = "string", Format = "binary" }
                            // 按需添加其他表单字段
                        }
                    }
                }
            }
        };
    }
}

2. 注册过滤器

在Swagger配置中添加该过滤器:

builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Example", Version = "v1" });
    c.OperationFilter<MultipartFormDataOperationFilter>();
});

此方案可手动生成符合要求的Swagger文档,但需维护过滤器与业务逻辑的一致性,扩展性较差。

内容的提问来源于stack exchange,提问作者Sergio Dalla Valle

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 07:40:39