【问题标题】:How do I deserialize a missing property to a default value in Json.NET?如何将缺失的属性反序列化为 Json.NET 中的默认值?
【发布时间】:2015-02-16 14:34:44
【问题描述】:

我有一个使用 DataContract 和 DataMember 属性注释的类。一些成员被标记为DataMember(IsRequired = true)。当我通过 Json.NET 的线路序列化实例,并且所需的对象成员具有空值时,输出中缺少它们的序列化值(这显然等同于 JSON 中的空值)。我没关系。

我创建了一种“回声”服务,它返回作为响应发送给它的数据。因此,此服务接收缺少成员(或空成员,具体取决于您如何看待它)的 JSON,然后将其直接发送回我的 Json.NET 客户端。通过 Fiddler(代理嗅探器)查看时,线路上的 JSON 在两个方向上看起来都相同。到目前为止一切顺利。

当原始 Json.NET 发送方收到 JSON 响应以对其进行反序列化时,序列化程序会抛出关于在 JSON 有效负载中找不到所需成员的异常:

Required property 'IAmRequired' not found in JSON. Path ''.

这很不幸,因为序列化程序因此无法反序列化它之前序列化的数据。

没有更改 DataContract 类以使成员不需要(出于多种原因我不想这样做),有没有办法让 Json.NET 将缺少的成员反序列化为默认值,例如 null?

这是我的反序列化代码:

HasRequired h = null;
JObject json = response as JObject; // hand waving here
try
{
    JsonSerializer ser = new JsonSerializer();
    ser.MissingMemberHandling = MissingMemberHandling.Ignore; // doesn't seem to help
    ser.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate; // doesn't seem to help
    ser.NullValueHandling = NullValueHandling.Include; // doesn't seem to help
    h = json.ToObject<HasRequired>(ser);
}
catch (Exception ex)
{
    // bummer, missing required members still
}

【问题讨论】:

  • 等等,你有标记为必需的成员,但他们真的不是必需的?
  • 它们是必需的......但只是为了满足 DataContractSerializer 的一些迟钝规则,以便能够处理 WCF 的序列化(对于 SOAP 绑定),并且不让类型看起来对客户端来说很糟糕。我知道你在说什么;如果不是 DC 串行器,它们将是可选的。对于我试图避免提及的 SOAP 序列化端,对象被序列化为 XML 空实例(它们被显式发送为空)。
  • 我明白了。我添加了一个对您有帮助的答案。

标签: json.net


【解决方案1】:

如果您有标记为[DataMember(Required = true)] 的属性并且您想要覆盖所需的行为,您可以执行以下操作:

  1. 您可以使用[JsonProperty(Required = Required.Default)] 标记这些相同的属性。这是因为 [JsonProperty] 在 Json.Net 中优先于 [DataMember]

    [DataContract]
    public class HasRequired
    {
        [DataMember(Required = true)]
        [JsonProperty(Required = Required.Default)]
        public string IAmRequired { get; set; }
    }
    
  2. 或者,您可以创建一个自定义 ContractResolver,以编程方式在每个属性上设置 Required = Required.Default

    class CustomResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty prop = base.CreateProperty(member, memberSerialization);
            prop.Required = Required.Default;
            return prop;
        }
    }
    

    要使用解析器,只需将序列化程序上的 ContractResolver 属性设置为自定义解析器的新实例:

    JsonSerializer ser = new JsonSerializer();
    ser = new CustomResolver();
    

【讨论】:

    【解决方案2】:

    这看起来像是我的代码中的一个真正的缺陷,需要为每个可为空但必需的成员重复,但它有效,并且似乎增加了可以忽略不计的开销。我在我原来的 sn-p 中的 try 块之前添加了这个:

    JToken maybeHasIt = null;
    if (!json.TryGetValue("IAmRequired", StringComparison.InvariantCultureIgnoreCase, out maybeHasIt))
    {
        json.Add("IAmRequired", null);
    }
    

    【讨论】:

      猜你喜欢
      • 2016-02-29
      • 2014-02-27
      • 2015-06-19
      • 2020-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-21
      相关资源
      最近更新 更多