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

ASP.NET Core Web API中POST请求多态JSON反序列化问题

ASP.NET Core Web API 多态模型绑定子类属性丢失问题解决

问题场景

使用C#开发ASP.NET Core Web API时,定义了包含基类Animal和子类Dog、Cat的多态模型,POST接口接收MyAnimals对象时,传入包含子类属性的JSON数据,控制器仅能获取基类属性,子类属性丢失。

模型类代码

public class MyAnimals
{
    public string Description { get; set; }
    public ICollection<Animal> Animals { get; set; }
}

public class Animal
{
    public string Name { get; set; }
}

public class Dog : Animal
{
    public string Says { get; set; }
}

public class Cat : Animal
{
    public string Likes { get; set; }
}

Web API POST处理方法

[HttpPost]
[AllowAnonymous]
public IActionResult PostAnimal([FromBody] MyAnimals myAnimals)
{
    return Ok();
}

期望请求JSON

{
    "description": "My favorite animals",
    "animals": 
        [
            {
                "likes": "Cheese",
                "name": "Tom"
            },
            {
                "says": "Bark",
                "name": "Pluto"
            }
        ]
}

实际解析结果(子类属性丢失)

{
    "description": "My favorite animals",
    "animals": [
        {
            "name": "Tom"
        },
        {
            "name": "Pluto"
        }
    ]
}

解决方案

问题根源是默认的System.Text.Json序列化器无法自动识别多态类型,需要显式配置多态支持或自定义类型转换逻辑。

方案一:使用内置多态特性(需客户端配合)

通过JsonDerivedType特性为基类指定子类映射,序列化器会根据类型鉴别符识别子类。

  1. 修改基类Animal,添加多态特性:
using System.Text.Json.Serialization;

[JsonDerivedType(typeof(Dog), typeDiscriminator: "Dog")]
[JsonDerivedType(typeof(Cat), typeDiscriminator: "Cat")]
public class Animal
{
    public string Name { get; set; }
}
  1. 客户端请求时,需在每个动物对象中添加类型鉴别符$type:
{
    "description": "My favorite animals",
    "animals": 
        [
            {
                "$type": "Cat",
                "likes": "Cheese",
                "name": "Tom"
            },
            {
                "$type": "Dog",
                "says": "Bark",
                "name": "Pluto"
            }
        ]
}

方案二:自定义JsonConverter(无需客户端修改)

编写自定义转换器,根据JSON中的属性自动判断并实例化对应子类,无需客户端额外传递类型标识。

  1. 创建AnimalConverter类:
using System.Text.Json;
using System.Text.Json.Serialization;

public class AnimalConverter : JsonConverter<Animal>
{
    public override Animal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using JsonDocument doc = JsonDocument.ParseValue(ref reader);
        var rootElement = doc.RootElement;

        // 根据属性判断子类类型
        if (rootElement.TryGetProperty("says", out _))
        {
            return JsonSerializer.Deserialize<Dog>(rootElement.GetRawText(), options);
        }
        else if (rootElement.TryGetProperty("likes", out _))
        {
            return JsonSerializer.Deserialize<Cat>(rootElement.GetRawText(), options);
        }
        // 默认返回基类实例
        return JsonSerializer.Deserialize<Animal>(rootElement.GetRawText(), options);
    }

    public override void Write(Utf8JsonWriter writer, Animal value, JsonSerializerOptions options)
    {
        // 序列化时按实际类型输出
        JsonSerializer.Serialize(writer, value, value.GetType(), options);
    }
}
  1. 注册转换器(两种方式二选一):
  • 方式一:在基类上添加特性
[JsonConverter(typeof(AnimalConverter))]
public class Animal
{
    public string Name { get; set; }
}
  • 方式二:在全局配置中添加转换器(.NET 6+ Program.cs)
var builder = WebApplication.CreateBuilder(args);

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

配置完成后,客户端直接发送原始的期望JSON即可,控制器能正确解析子类属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 20:55:21