【问题标题】:Detect if deserialized object is missing a field with the JsonConvert class in Json.NET检测反序列化的对象是否缺少 Json.NET 中 JsonConvert 类的字段
【发布时间】:2014-01-28 14:57:19
【问题描述】:

我正在尝试使用 Json.NET 反序列化一些 JSON 对象。然而,我发现,当我反序列化一个没有我要查找的属性的对象时,不会引发任何错误,但是当我访问它们时会为这些属性返回一个默认值。当我反序列化错误类型的对象时,我能够检测到这一点很重要。示例代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Json_Fail_Test
{
    class Program
    {
        [JsonObject(MemberSerialization.OptOut)]
        private class MyJsonObjView
        {
            [JsonProperty("MyJsonInt")]
            public int MyJsonInt { get; set; }
        }

        const string correctData = @"
        {
            'MyJsonInt': 42
        }";

        const string wrongData = @"
        {
            'SomeOtherProperty': 'fbe8c20b'
        }";

        static void Main(string[] args)
        {
            var goodObj = JsonConvert.DeserializeObject<MyJsonObjView>(correctData);
            System.Console.Out.WriteLine(goodObj.MyJsonInt.ToString());

            var badObj = JsonConvert.DeserializeObject<MyJsonObjView>(wrongData);
            System.Console.Out.WriteLine(badObj.MyJsonInt.ToString());
        }
    }
}

这个程序的输出是: 42 0

我宁愿抛出异常而不是静默失败。除此之外,有没有办法检测序列化是否找不到参数?

我知道我可以使用 Json 对象解析数据,然后使用键值查找检查参数,但我所在的代码库使用上面的模式,如果可能的话,我希望保持一致。

【问题讨论】:

    标签: c# .net json serialization json.net


    【解决方案1】:

    Json.Net 序列化程序有一个MissingMemberHandling 设置,您可以将其设置为Error。 (默认为Ignore。)这将导致序列化程序在反序列化过程中遇到目标类中没有对应属性的JSON属性时抛出JsonSerializationException

    static void Main(string[] args)
    {
        try
        {
            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.MissingMemberHandling = MissingMemberHandling.Error;
    
            var goodObj = JsonConvert.DeserializeObject<MyJsonObjView>(correctData, settings);
            System.Console.Out.WriteLine(goodObj.MyJsonInt.ToString());
    
            var badObj = JsonConvert.DeserializeObject<MyJsonObjView>(wrongData, settings);
            System.Console.Out.WriteLine(badObj.MyJsonInt.ToString());
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.GetType().Name + ": " + ex.Message);
        }
    }
    

    结果:

    42
    JsonSerializationException: Could not find member 'SomeOtherProperty' on object
    of type 'MyJsonObjView'. Path 'SomeOtherProperty', line 3, position 33.
    

    请参阅:MissingMemberHandling setting

    【讨论】:

    • 我实际上在文档中发现了设置类,但我必须略过该属性。我是个废话速读者。非常感谢;这是完美的。
    • @BrianRogers 谢谢。这对我帮助很大。是否有任何链接可以分享进一步研究 JSON 解析,尤其是缺失值和 Null 值处理问题?
    • 我有一个非常相似的问题。如果 JSON 中缺少目标类的一个成员,反序列化器将忽略它并将其设置为 null。即使 MissingMember 设置设置为错误。
    • 已经找到解决方案。使用属性将我的成员标记为必需。
    • 示例是:将空的 json 字符串“{}”反序列化为任何类型。它将类型中的所有值设置为空。但如果类型与 json 不匹配,我想要一个例外。
    【解决方案2】:

    只需将[JsonProperty(Required = Required.Always)] 添加到所需的属性中,如果在反序列化时该属性不存在,它将引发异常。

    [JsonProperty(Required = Required.Always)]
     public int MyJsonInt { get; set; }
    

    【讨论】:

    • 这解决了一个互补的问题。如果您的 model 具有您的 JSON 没有的属性,并且您希望这是一个错误,请使用 [JsonProperty(Required = Required.Always)]。见:JsonPropertyAttribute required。如果您的 JSON 具有您的 model 没有的属性,并且您希望这是一个错误,请使用 MissingMemberHandling = MissingMemberHandling.Error
    【解决方案3】:

    将以下属性放在必需的属性上:

    [DataMember(IsRequired = true)]
    

    如果成员不存在,它将抛出 Newtonsoft.Json.JsonSerializationException。

    正如 Brian 下面建议的那样,你的班级也需要这个属性:

    [DataContract]
    

    【讨论】:

    • 你确定吗?我尝试添加属性,没有给出异常。并且程序仍然打印 0。
    • 这个解决方案只有在你的班级有 [DataContract] 而你的成员没有 [JsonProperty] 时才有效。 (JsonProperty 覆盖DataMember。)但是,您可以将[JsonProperty] 属性上的Required 参数设置为Required.Always 来完成同样的事情。
    • @DubiousPusher 属性应该可以为空。然后它会工作。
    【解决方案4】:

    只需在定义类中使用问号“?”定义您的成员int?:

    private class MyJsonObjView
    {
        [JsonProperty("MyJsonInt")]
        public int? MyJsonInt { get; set; }
    }
    

    当它没有被初始化时,它只是null,否则它就是一个有效值。这使您可以选择设置并根据每个设置对其进行评估。

    【讨论】:

    • 这无法区分属性在 JSON 中何时丢失或设置为 null。
    【解决方案5】:

    正如@dbc 在 cmets 中所说:

    • 反序列化时:

    如果您的模型具有 JSON 没有的属性,并且您希望这是错误,请使用 [JsonProperty(Required = Required.Always)]

    • 在序列化时:

    如果您的 JSON 具有您的模型没有的属性,并且您希望它成为错误,请使用 MissingMemberHandling = MissingMemberHandling.Error

    当属性类型为可为空时,也使用[DataMember(IsRequired = true)] 反序列化错误是真的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多