在下面的代码中,我使用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 { }
}
答案 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 ''
例外。