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

ASP.NET Core Web API中如何为动态JSON构建合适的C#类模型

实现方案:多态模型 + 自定义JSON转换器

该方案完全匹配你的需求,既不会出现多余的null属性,也能通过枚举约束类型取值,完美适配动态JSON结构。

第一步:定义枚举类型

先把两类动态type定义为枚举,后续可以通过特性控制序列化输出为字符串而非数字:

// Source类型枚举
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum SourceType
{
    Land,
    Water,
    Air
}

// 修改项类型枚举
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum ModifyType
{
    Performance,
    Aesthetic,
    Functional
}

第二步:定义多态基类和派生类

所有公共属性放在抽象基类,不同type独有的属性放在对应派生类,完全避免冗余字段:

Source相关类

// Source抽象基类,仅放公共字段
public abstract class SourceBase
{
    public SourceType Type { get; set; }
}

// 陆地类型Source独有属性
public class LandSource : SourceBase
{
    public string Speed { get; set; }
}

// 空中类型Source独有属性
public class AirSource : SourceBase
{
    public string Height { get; set; }
    public string NumberLandings { get; set; }
}

// 水上类型Source独有属性
public class WaterSource : SourceBase
{
    // 自行补充水上场景独有的属性
}

Modify修改项相关类

// 修改项抽象基类,仅放公共字段
public abstract class ModifyItemBase
{
    public ModifyType Type { get; set; }
}

// 性能类修改项独有属性
public class PerformanceModify : ModifyItemBase
{
    public string Brakes { get; set; }
    public string Turbo { get; set; }
    public string Suspension { get; set; }
}

// 功能类修改项独有属性
public class FunctionalModify : ModifyItemBase
{
    public string Electric { get; set; }
    public string Applications { get; set; }
}

// 外观类修改项独有属性
public class AestheticModify : ModifyItemBase
{
    // 自行补充外观场景独有的属性
}

第三步:实现自定义多态JSON转换器

以ASP.NET Core默认的System.Text.Json为例,写两个转换器自动根据type字段匹配对应派生类,完成序列化/反序列化:

Source类型转换器

public class SourceConverter : JsonConverter<SourceBase>
{
    public override bool CanConvert(Type typeToConvert) => typeof(SourceBase).IsAssignableFrom(typeToConvert);

    public override SourceBase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using var doc = JsonDocument.ParseValue(ref reader);
        var root = doc.RootElement;
        var typeStr = root.GetProperty("type").GetString();
        var sourceType = Enum.Parse<SourceType>(typeStr);

        return sourceType switch
        {
            SourceType.Land => JsonSerializer.Deserialize<LandSource>(root.GetRawText(), options),
            SourceType.Air => JsonSerializer.Deserialize<AirSource>(root.GetRawText(), options),
            SourceType.Water => JsonSerializer.Deserialize<WaterSource>(root.GetRawText(), options),
            _ => throw new NotSupportedException($"不支持的Source类型:{typeStr}")
        };
    }

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

修改项类型转换器

public class ModifyItemConverter : JsonConverter<ModifyItemBase>
{
    public override bool CanConvert(Type typeToConvert) => typeof(ModifyItemBase).IsAssignableFrom(typeToConvert);

    public override ModifyItemBase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using var doc = JsonDocument.ParseValue(ref reader);
        var root = doc.RootElement;
        var typeStr = root.GetProperty("type").GetString();
        var modifyType = Enum.Parse<ModifyType>(typeStr);

        return modifyType switch
        {
            ModifyType.Performance => JsonSerializer.Deserialize<PerformanceModify>(root.GetRawText(), options),
            ModifyType.Functional => JsonSerializer.Deserialize<FunctionalModify>(root.GetRawText(), options),
            ModifyType.Aesthetic => JsonSerializer.Deserialize<AestheticModify>(root.GetRawText(), options),
            _ => throw new NotSupportedException($"不支持的修改项类型:{typeStr}")
        };
    }

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

第四步:注册转换器并定义顶层模型

注册转换器

在Program.cs中配置JSON选项,注册上述转换器适配系统自带的模型绑定:

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new SourceConverter());
        options.JsonSerializerOptions.Converters.Add(new ModifyItemConverter());
        // 配置大小写不敏感,适配JSON驼峰命名
        options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
        options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    });

顶层模型定义

public class RootModel
{
    public PropertiesModel Properties { get; set; }
}

public class PropertiesModel
{
    public SourceBase Source { get; set; }
    public List<ModifyItemBase> Modify { get; set; }
}

方案优势

  • 无冗余属性:每个派生类仅包含对应类型独有的字段,不会出现永远为null的无效属性
  • 类型安全:通过枚举和派生类约束取值,编译期即可检查出类型错误
  • 自动适配:转换器自动根据type字段匹配对应派生类,不需要手动处理转换逻辑
  • 原生兼容:完全适配ASP.NET Core自带的模型绑定,接口入参直接用RootModel接收即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 14:15:01