使用Json.Net反序列化未知类型时出现意外错误

时间:2017-03-29 21:42:36

标签: json.net

在下面的代码中,我使用Json.Net序列化对象。这个Json嵌入了类型名称。然后我更改其中一个类型名称以引发错误(这是一个测试,我正在处理现有项目中的实际问题)。当我反序列化Json时,我期望得到一个具有带有fiddled类型名称的属性的null值的对象。相反,序列化器会变形并返回null。我的期望是否正确?我可以以某种方式更改设置,以便为根对象获取非null对象吗?请注意,我得到的第二个错误表明序列化程序中存在错误。

static public class JsonTest
{
    static public void Test()
    {
        // Create test object
        A a = new A
        {
            MyTest = new MyTest(),
        };

        // Serialize it. 
        string json = JsonConvert.SerializeObject(a, new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.Auto
        });

        // Fiddle class name to induce error
        json = json.Replace("+MyTest", "+MyTest2"); 

        // Before: {"MyTest":{"$type":"<Namespace>.JsonTest+MyTest, <Assembly>"}}
        // After: {"MyTest":{"$type":"<Namespace>.JsonTest+MyTest2, <Assembly>"}}

        // Deserialize
        A a2 = JsonConvert.DeserializeObject<A>(json, new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.Auto,
            Error = (object sender, ErrorEventArgs e) =>
            {
                e.ErrorContext.Handled = true; // Should have only one error: the unrecognized Type
            }
        });

        // A second error occurs: Error = {Newtonsoft.Json.JsonSerializationException: Additional text found in JSON string after finishing deserializing object....
        // a2 is null
    }

    public class A
    {
        public ITest MyTest { get; set; }
    }

    public interface ITest { }
    public class MyTest : ITest { }
}

1 个答案:

答案 0 :(得分:1)

<强>更新

issue已在10.0.2的Json.NET this submission中修复。

原始答案

这看起来像是Json.NET中的一个错误。如果我设置JsonSerializerSettings.MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead,问题就会消失:

// Deserialize
A a2 = JsonConvert.DeserializeObject<A>(json, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto,
    MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead,
    Error = (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs e) =>
    {
        Debug.WriteLine(e.ErrorContext.Path);
        e.ErrorContext.Handled = true; // Should have only one error: the unrecognized Type
    }
});

Debug.Assert(a2 != null); // No assert. 

但是,没有必要打开此设置,这样可以读取位于JSON对象中任何位置的"$type"元数据属性,而不仅仅是第一个属性。很可能它巧合地修复了这个bug,因为它需要在开始反序列化之前预先加载整个JSON对象。

如果你愿意,你可以report an issue

调试一下,问题似乎是,因为无法构造内部MyTest对象,所以在填充外部对象A时由JsonSerializerInternalReader.PopulateObject()捕获并处理异常。因此,JsonReader不会超过内部嵌套对象,使读取器和序列化器处于不一致状态。这解释了第二个例外和最终Additional text found in JSON string after finishing deserializing object. Path ''例外。