.NET API中配置Swagger按ContentType展示不同模型类的方法
问题描述
我有一个.NET API项目,其中AddPet接口配置了[Consumes("multipart/form-data", "application/json")],并分别使用[FromForm] PetRequestInfo和[FromBody] PetJsonRequestInfo作为参数。但当前Swagger UI及生成的swagger.json文件中,无论请求ContentType是什么,仅展示PetJsonRequestInfo模型类。需要配置Swagger,使其根据请求ContentType(multipart/form-data和application/json)正确展示对应的模型类。
相关接口代码
public class PetRequestInfo { // File upload specific to multipart/form-data public IFormFile PetImage { get; set; } // Common properties public string PetName { get; set; } public int PetAge { get; set; } } public class PetJsonRequestInfo { // No file upload, JSON only // Common properties public string PetName { get; set; } public int PetAge { get; set; } } // POST: api/pets/add [HttpPost("add")] [Consumes("multipart/form-data", "application/json")] public async Task<ActionResult<PetAdded>> AddPet([FromForm] PetRequestInfo petRequestInfo, [FromBody] PetJsonRequestInfo petJsonRequestInfo) { // Validate inputs if (petRequestInfo == null || petJsonRequestInfo == null) { return BadRequest("Invalid request data."); } // logic will be here... }
当前swagger.json异常片段
"/v1/Pet/add": { "post": { "summary": "Add a new pet.", "requestBody": { "description": "The pet request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PetJsonRequestInfo" } }, "multipart/form-data": { "schema": { "$ref": "#/components/schemas/PetJsonRequestInfo" } }, "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/PetJsonRequestInfo" } } } }, "responses": { "201": { "description": "Created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PetAdded" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResult" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResult" } } } } } } }
期望的swagger.json片段
"requestBody": { "description": "The pet request body.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PetJsonRequestInfo" } }, "multipart/form-data": { "schema": { "$ref": "#/components/schemas/PetRequestInfo" } }, "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/PetRequestInfo" } } } }
解决方案
问题根源是Swagger默认会合并多个请求参数的模型,无法自动区分不同ContentType对应的参数。可以通过以下两种方式解决:
方式一:拆分接口(推荐)
将两种ContentType的请求拆分为独立接口,各自对应参数模型,Swagger会自动生成正确的文档:
// 处理application/json请求 [HttpPost("add/json")] [Consumes("application/json")] public async Task<ActionResult<PetAdded>> AddPetJson([FromBody] PetJsonRequestInfo petJsonRequestInfo) { if (petJsonRequestInfo == null) { return BadRequest("Invalid request data."); } return await AddPetInternal(petJsonRequestInfo.PetName, petJsonRequestInfo.PetAge, null); } // 处理multipart/form-data请求 [HttpPost("add/form")] [Consumes("multipart/form-data")] public async Task<ActionResult<PetAdded>> AddPetForm([FromForm] PetRequestInfo petRequestInfo) { if (petRequestInfo == null) { return BadRequest("Invalid request data."); } return await AddPetInternal(petRequestInfo.PetName, petRequestInfo.PetAge, petRequestInfo.PetImage); } // 内部共享业务逻辑 private async Task<ActionResult<PetAdded>> AddPetInternal(string petName, int petAge, IFormFile petImage) { // 核心业务逻辑实现 return CreatedAtAction(nameof(GetPet), new { id = 1 }, new PetAdded { Id = 1, Name = petName, Age = petAge }); }
方式二:自定义Swagger操作过滤器
如果不想拆分接口,可通过实现IOperationFilter手动修改Swagger文档的requestBody内容:
- 创建自定义过滤器类:
using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System.Linq; public class RequestContentTypeFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { // 定位目标接口 if (context.ApiDescription.ActionDescriptor.DisplayName.Contains("AddPet")) { // 生成两个模型的Schema引用 var formSchema = context.SchemaGenerator.GenerateSchema(typeof(PetRequestInfo), context.SchemaRepository); var jsonSchema = context.SchemaGenerator.GenerateSchema(typeof(PetJsonRequestInfo), context.SchemaRepository); // 更新不同ContentType对应的Schema operation.RequestBody.Content["multipart/form-data"].Schema = formSchema; operation.RequestBody.Content["application/x-www-form-urlencoded"].Schema = formSchema; operation.RequestBody.Content["application/json"].Schema = jsonSchema; } } }
- 在Program.cs中注册过滤器:
builder.Services.AddSwaggerGen(c => { c.OperationFilter<RequestContentTypeFilter>(); // 其他Swagger配置项 });
注意:使用该方式时,需要调整原接口的参数校验逻辑(比如当请求为application/json时,petRequestInfo会为null,不能直接判断两个参数都不为null)。
内容的提问来源于stack exchange,提问作者Bruno F
相关产品推荐
相关产品推荐

