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

在.NET控制器中如何让FromBody参数支持类继承以正确解析子类?

解决方案

首先明确问题根因:ASP.NET Core 默认的JSON序列化器仅会按属性声明的BaseSchema类型进行字段解析,不会自动识别子类类型,因此子类独有的属性会被丢弃。下面提供3种可落地的实现方案:

方案1:使用System.Text.Json原生多态支持(.NET 7+ 推荐)

.NET 7及以上版本的System.Text.Json原生支持多态序列化/反序列化,只需给父类添加特性标注即可:

// 引入命名空间 using System.Text.Json.Serialization;
[JsonPolymorphic(TypeDiscriminatorPropertyName = "SchemaType")]
[JsonDerivedType(typeof(BaseSchema), typeDiscriminator: "Base")]
[JsonDerivedType(typeof(SingleLineSchema), typeDiscriminator: "SingleLine")]
public class BaseSchema
{
    public DataType Type { set; get; }
    public string Label { set; get; }
    public bool Visibility { set; get; }
    public string Hint { set; get; }
}

请求传参时在JSON中添加SchemaType判别字段即可:

{
  "Id": "xxx",
  "FormSchema": {
    "SchemaType": "SingleLine",
    "Type": 1,
    "Label": "单行文本",
    "Visibility": true,
    "Hint": "请输入内容",
    "CustomFieldExample": "自定义属性值"
  }
}

反序列化后会自动生成对应的子类实例,不会丢失属性。

方案2:自定义JsonConverter(兼容所有.NET版本)

如果是.NET 6及以下版本,或者不想新增判别字段,可以自定义JSON转换器,根据已有字段(比如你已有的DataType枚举值)判断要实例化的子类:

public class BaseSchemaConverter : JsonConverter<BaseSchema>
{
    public override BaseSchema? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 先加载JsonElement判断DataType值
        using var jsonDoc = JsonDocument.ParseValue(ref reader);
        var root = jsonDoc.RootElement;
        var dataType = root.GetProperty("Type").GetInt32(); // 按你的DataType枚举实际值调整
        return dataType switch
        {
            // 假设DataType.SingleLine对应单行文本子类
            (int)DataType.SingleLine => JsonSerializer.Deserialize<SingleLineSchema>(root.GetRawText(), options),
            // 其他子类对应分支
            _ => JsonSerializer.Deserialize<BaseSchema>(root.GetRawText(), options)
        };
    }

    public override void Write(Utf8JsonWriter writer, BaseSchema value, JsonSerializerOptions options)
    {
        JsonSerializer.Serialize(writer, value, value.GetType(), options);
    }
}

然后在Program.cs中注册转换器:

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

方案3:直接接收JSON对象手动转换

如果不想改序列化配置,可以将DTO中的属性类型改为JsonElement(System.Text.Json)或JObject(Newtonsoft.Json),业务层手动转成对应子类:

public class UpdateFormSchemaRequestDto
{
    public string Id { set; get; }
    public JsonElement FormSchema { set; get; }
}

业务层转换代码:

public async Task<Response> UpdateFormSchema(UpdateFormSchemaRequestDto dto)
{
    BaseSchema schema;
    var dataType = dto.FormSchema.GetProperty("Type").GetInt32();
    if (dataType == (int)DataType.SingleLine)
    {
        schema = dto.FormSchema.Deserialize<SingleLineSchema>();
    }
    else
    {
        schema = dto.FormSchema.Deserialize<BaseSchema>();
    }
    // 后续业务逻辑
}

注意事项

  • 如果使用Newtonsoft.Json的TypeNameHandling配置实现多态,不要对外网公开接口,避免恶意JSON payload触发反序列化注入漏洞。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 07:06:08