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

ASP.NET Core Web API多态请求体:如何让Swagger UI支持类型选择

ASP.NET Core Web API Swagger多态请求体类型选择问题

我正在开发ASP.NET Core Web API,需要允许客户端发送PUT请求时选择多种派生类型。已经通过基类、派生类配置了多态,并用自定义JsonConverter处理序列化,但Swagger UI只显示First类型的请求体选项,需要开启类型选择功能。

以下是我的模型、控制器及配置代码:

// Base class and derived classes
public abstract class Base
{
    public Type Type { get; set; }
}

public enum Type
{
    First,
    Second
}

[JsonConverter(typeof(FirstConverter))]
public class First : Base
{
    public string Value { get; set; }
}

[JsonConverter(typeof(SecondConverter))]
public class Second : Base
{
    public string Data { get; set; }
}

// TestController
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    [HttpPut("/base")]
    public IActionResult First([FromBody] Base parameters)
    {
        return Ok(parameters);
    }
}

// Custom JsonConverter for polymorphism
public class TestJsonConverter : JsonConverter<Base>
{
    // Custom converter logic
}

// Swagger Configuration in Startup.cs or Program.cs
builder.Services.AddSwaggerGen(options =>
{
    options.UseOneOfForPolymorphism();
    options.UseAllOfForInheritance();
    options.SchemaFilter<NotificationSettingsSchemaFilter>();
});

当前Swagger UI未提供First或Second类型的选择选项,请问我的Swagger配置缺失了什么?如何修改配置,让UI支持PUT请求体的类型选择?


问题原因

你的配置存在几个关键缺失:

  • 未将自定义TestJsonConverter注册到系统,Swagger无法识别多态类型映射逻辑
  • 未显式声明Base类的派生类型,Swagger仅能识别到标记了特性的First类
  • 派生类上单独标注的[JsonConverter]特性与全局多态转换器冲突

修复步骤

1. 移除派生类的JsonConverter特性

删除First和Second类上的[JsonConverter]特性,全局转换器会统一处理多态序列化:

// 修正后的First类
public class First : Base
{
    public string Value { get; set; }
}

// 修正后的Second类
public class Second : Base
{
    public string Data { get; set; }
}

2. 注册全局多态转换器

在Program.cs(或Startup.cs)中,将TestJsonConverter添加到Json序列化配置:

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new TestJsonConverter());
    });

3. 配置Swagger显式识别派生类型

修改Swagger配置,添加自定义SchemaFilter声明Base的派生类,确保Swagger能渲染类型选择器:

builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo { Title = "Test API", Version = "v1" });
    // 启用多态支持特性
    options.UseOneOfForPolymorphism();
    options.UseAllOfForInheritance();
    // 添加自定义SchemaFilter
    options.SchemaFilter<BasePolymorphismSchemaFilter>();
});

// 自定义SchemaFilter,声明Base的派生类型
public class BasePolymorphismSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (context.Type == typeof(Base))
        {
            // 注册所有派生类
            schema.OneOf = new List<OpenApiSchema>
            {
                context.SchemaGenerator.GenerateSchema(typeof(First), context.SchemaRepository),
                context.SchemaGenerator.GenerateSchema(typeof(Second), context.SchemaRepository)
            };
            schema.Description = "请选择请求体类型:First或Second";
            // 添加discriminator配置,让Swagger识别类型字段
            schema.Discriminator = new OpenApiDiscriminator
            {
                PropertyName = "Type",
                Mapping = new Dictionary<string, string>
                {
                    { nameof(Type.First), "#/components/schemas/First" },
                    { nameof(Type.Second), "#/components/schemas/Second" }
                }
            };
        }
    }
}

4. 完善TestJsonConverter逻辑

确保自定义转换器能根据Type枚举值正确反序列化对应派生类,示例实现:

public class TestJsonConverter : JsonConverter<Base>
{
    public override Base Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using var doc = JsonDocument.ParseValue(ref reader);
        if (!doc.RootElement.TryGetProperty(nameof(Type), out var typeElement))
            throw new JsonException("缺少Type字段");
        
        if (!Enum.TryParse<Type>(typeElement.GetString(), out var type))
            throw new JsonException("无效的Type值");
        
        return type switch
        {
            Type.First => doc.RootElement.Deserialize<First>(options),
            Type.Second => doc.RootElement.Deserialize<Second>(options),
            _ => throw new JsonException("不支持的请求体类型")
        };
    }

    public override void Write(Utf8JsonWriter writer, Base value, JsonSerializerOptions options)
    {
        // 序列化时使用实际派生类类型
        JsonSerializer.Serialize(writer, value, value.GetType(), options);
    }
}

完成以上修改后,Swagger UI会在PUT请求的请求体区域显示类型选择下拉框,支持选择First或Second类型,同时请求体结构会自动切换为对应类型的字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 15:37:12