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

如何动态反序列化API返回JSON的可变Body至对应C#模型?

问题描述

我从API获取的JSON格式如下:

{
   "header":{
      "message_type":"message_type",
      "notification_type":"notification_type"
   },
   "body":{
      "id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "related_entity_type":"inbound_funds"
   }
}

问题在于body可以包含任意数量和类型的属性,而且我已经有对应每种body类型的C#模型。有没有高效的方法能动态解析并把这些对象反序列化为对应的C#模型?

我尝试了以下代码,但Body无法在运行时完成反序列化:

public class PushNotification : Body
{
    [JsonProperty("header")]
    public Header Header { get; set; }

    [JsonProperty("body")]
    public Body Body { get; set; }
}

public class Body
{
}
解决方案

可以利用**Json.NET(Newtonsoft.Json)**的特性,先解析头部信息确定Body类型,再针对性反序列化Body内容,这是最常用且高效的方案。

步骤1:修正基础模型

把PushNotification里的Body改成JToken类型,先暂存原始JSON内容,避免提前丢失结构:

public class PushNotification
{
    [JsonProperty("header")]
    public Header Header { get; set; }

    [JsonProperty("body")]
    public JToken BodyRaw { get; set; } // 暂存原始Body的JSON结构
}

public class Header
{
    [JsonProperty("message_type")]
    public string MessageType { get; set; }

    [JsonProperty("notification_type")]
    public string NotificationType { get; set; }
}

步骤2:建立类型映射字典

提前把API返回的标识(比如notification_type或Body里的related_entity_type)和对应的C#模型做绑定,方便快速查找:

// 全局或局部定义类型映射
private static readonly Dictionary<string, Type> BodyTypeMap = new Dictionary<string, Type>
{
    {"inbound_funds", typeof(InboundFundsBody)},
    {"outbound_payouts", typeof(OutboundPayoutsBody)},
    // 后续新增Body类型直接在这里添加
};

// 示例Body模型
public class InboundFundsBody
{
    [JsonProperty("id")]
    public Guid Id { get; set; }

    [JsonProperty("related_entity_type")]
    public string RelatedEntityType { get; set; }

    // 该类型专属的其他属性
}

public class OutboundPayoutsBody
{
    [JsonProperty("id")]
    public Guid Id { get; set; }

    [JsonProperty("amount")]
    public decimal Amount { get; set; }

    // 该类型专属的其他属性
}

步骤3:动态反序列化Body

先反序列化整个通知拿到头部信息,再根据映射字典找到对应模型,最后把原始Body内容转成目标类型:

string apiResponse = "API返回的JSON字符串";

// 1. 先反序列化整体,拿到头部和原始Body
var pushNotify = JsonConvert.DeserializeObject<PushNotification>(apiResponse);

// 2. 确定要使用的Body类型(这里用header里的notification_type,也可以从BodyRaw取related_entity_type)
string typeKey = pushNotify.Header.NotificationType;
// 或者:string typeKey = pushNotify.BodyRaw["related_entity_type"].ToString();

if (BodyTypeMap.TryGetValue(typeKey, out Type targetType))
{
    // 3. 把原始Body反序列化为目标模型
    object body = JsonConvert.DeserializeObject(pushNotify.BodyRaw.ToString(), targetType);

    // 强转后使用
    if (body is InboundFundsBody inboundBody)
    {
        // 处理入金业务逻辑
        Console.WriteLine($"入金记录ID:{inboundBody.Id}");
    }
    else if (body is OutboundPayoutsBody outboundBody)
    {
        // 处理出金业务逻辑
        Console.WriteLine($"出金金额:{outboundBody.Amount}");
    }
}
else
{
    // 处理未知类型的异常
    throw new NotSupportedException($"未定义的Body类型:{typeKey}");
}

进阶优化:自定义JsonConverter

如果想一次性完成反序列化,不用分步处理,可以自定义转换器,让反序列化过程自动识别Body类型:

public class PushNotificationConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(TypedPushNotification);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);

        // 先解析Header
        var header = jo["header"].ToObject<Header>(serializer);

        // 获取Body类型并验证
        string typeKey = header.NotificationType;
        if (!BodyTypeMap.TryGetValue(typeKey, out Type bodyType))
        {
            throw new NotSupportedException($"不支持的通知类型:{typeKey}");
        }

        // 解析Body
        object body = jo["body"].ToObject(bodyType, serializer);

        return new TypedPushNotification
        {
            Header = header,
            Body = body
        };
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException(); // 不需要序列化可留空
    }
}

// 定义带动态Body的通知类
public class TypedPushNotification
{
    public Header Header { get; set; }
    public object Body { get; set; }
}

使用时直接指定转换器即可:

var typedNotify = JsonConvert.DeserializeObject<TypedPushNotification>(apiResponse, new PushNotificationConverter());

注意事项

  • 类型映射的键要和API返回的标识完全匹配(大小写敏感)
  • 如果用.NET Core内置的System.Text.Json,思路类似,用JsonElement代替JToken即可
  • 务必处理未知Body类型的情况,避免程序崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 20:45:44