You need to enable JavaScript to run this app. .NET 4.5下如何用Newtonsoft.Json实现灵活嵌套JSON的存储与解析
优惠活动
大模型
产品
解决方案
定价
更多

.NET 4.5下如何用Newtonsoft.Json实现灵活嵌套JSON的存储与解析

问题根源定位

当前流程存在双重序列化转义问题:

  1. 第一次序列化:将ExpiryTriggerJson实例转为JSON字符串,赋值给TriggerJson.Trigger属性
  2. 第二次序列化:将整个List<TriggerJson>序列化为最终存储的大JSON时,会把Trigger属性的string值当作普通文本处理,自动转义内部所有双引号,最终形成带大量冗余转义符的输出
    反序列化阶段的报错本质是:外层JSON解析完成后,obj.Trigger节点是纯文本字符串类型(存的是带转义的JSON片段),不是结构化的JSON对象节点,直接调用ToObject<T>()自然无法匹配ExpiryTriggerJson的结构。
可落地实现方案

完全适配.NET 4.5运行环境,同时保留Trigger为string类型、支持按TriggerType动态匹配结构的灵活存储需求:

方案1:从根源避免双层转义(推荐,适配新数据写入)

因为Trigger字段是string类型,默认序列化时会被当作普通字符串值处理,需要通过自定义转换器让它在序列化时以原始JSON片段的形式写入,而非转义字符串:

  1. 编写适配旧框架的原始JSON转换器:
public class RawJsonStringConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var jsonStr = value as string;
        if (!string.IsNullOrWhiteSpace(jsonStr))
        {
            // 直接将字符串内容作为原始JSON片段写入,不做转义
            writer.WriteRawValue(jsonStr);
        }
        else
        {
            writer.WriteNull();
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // 读取时把结构化JSON节点转回字符串,保留灵活存储特性
        if (reader.TokenType == JsonToken.Null) return null;
        return JRaw.Create(reader).ToString();
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string);
    }
}
  1. 给TriggerJson的Trigger属性标记转换器:
public class TriggerJson
{        
    public string TriggerType { get; set; }        
    public string ConfiguredBy { get; set; }
    // 标记自定义转换器,避免双层转义
    [JsonConverter(typeof(RawJsonStringConverter))]
    public string Trigger { get; set; }
}

调整完成后,原有的写入逻辑完全不需要修改,最终生成的存储JSON会变为结构化的嵌套格式,无冗余转义符:

[
  {
    "TriggerType": "ExpiryTrigger",
    "ConfiguredBy": "acd1ac353ac44e078aaef8ce6479a4c6",
    "Trigger": {
      "ActionType": "CreateReminderTask",
      "Recipients": [
        {
          "Id": "70050a95-f31b-41b7-9b49-0688fa76dba5",
          "Name": "blah blah",
          "IsTag": false
        }
      ]
    }
  }
]

此时原有的反序列化逻辑obj.Trigger.ToObject<ExpiryTriggerJson>()可以正常运行,因为obj.Trigger已经是结构化的JSON节点,不再是纯文本字符串。

方案2:兼容存量转义格式数据

如果系统已经存在大量旧逻辑写入的带转义的存量数据,不需要调整序列化逻辑,只需修改反序列化阶段的节点判断逻辑即可:

JArray jsonObj = JArray.Parse(triggersJson);
foreach (dynamic obj in jsonObj)
{
    if (obj.TriggerType == ExpiryTriggerType)
    {
        ExpiryTriggerJson triggerData;
        // 判断Trigger节点类型,分别处理新旧格式
        if (obj.Trigger.Type == JTokenType.String)
        {
            // 旧格式:取出被转义的字符串,先反序列化为目标类型
            var innerJson = (string)obj.Trigger;
            triggerData = JsonConvert.DeserializeObject<ExpiryTriggerJson>(innerJson);
        }
        else
        {
            // 新格式:结构化节点直接转换
            triggerData = obj.Trigger.ToObject<ExpiryTriggerJson>();
        }
    }
}
实现注意事项
  • 以上实现完全兼容.NET 4.5版本配套的Newtonsoft.Json类库,无需升级运行时框架
  • 整个实现过程没有为TriggerJson硬编码嵌套的触发结构,后续新增其他触发类型时,只需传入对应结构的JSON字符串给Trigger字段即可,完全符合灵活JSON存储的设计目标
  • 可在RawJsonStringConverter的写入逻辑中增加JSON合法性校验,避免非法格式的字符串导致序列化失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 13:27:03