使用NewtonSoft.JSON序列化接口/抽象对象

反序列化接口和抽象属性的一种方法是通过在序列化和反序列化期间将TypeNameHandling设置为Auto来实现。 但是,当我在直接序列化和反序列化接口对象时尝试相同的操作时,它不起作用 –

interface ISample { string Key { get; set; } } class A : ISample { public string Key { get; set; } public A(string key) { this.Key = key; } } class B : ISample { public string Key { get; set; } public B(string key) { this.Key = key; } } 

序列化和反序列化代码 –

 ISample a = new A("keyA"); ISample b = new B("keyB"); var settings = new JsonSerializerSettings(); settings.TypeNameHandling = TypeNameHandling.Auto; var stringA = JsonConvert.SerializeObject(a, settings); var stringB = JsonConvert.SerializeObject(b, settings); Console.WriteLine(stringA); Console.WriteLine(stringB); a = JsonConvert.DeserializeObject(stringA, settings); b = JsonConvert.DeserializeObject(stringB, settings); 

我注意到即使设置TypeNameHandling.Auto,序列化字符串中也不存在类型信息。 但是,将TypeNameHandling设置为Object或All可以正常工作。

我错过了一些基本的东西吗?

在根级别TypeNameHandling.Auto的多态对象启用$type信息的输出,请使用以下重载: JsonConvert.SerializeObject Method (Object, Type, JsonSerializerSettings) 。 来自文档 :

 public static string SerializeObject( Object value, Type type, JsonSerializerSettings settings ) 

type类型:System.Type要序列化的值的类型。 当TypeNameHandling为Auto时,如果值的类型不匹配,则使用此参数写出类型名称。 指定类型是可选的。

在你的情况下,你会这样做:

 var stringA = JsonConvert.SerializeObject(a, typeof(ISample), settings); var stringB = JsonConvert.SerializeObject(b, typeof(ISample), settings); Console.WriteLine(stringA); Console.WriteLine(stringB); 

得到结果:

 {"$type":"Tile.TestJsonDotNet.A, Tile","Key":"keyA"} {"$type":"Tile.TestJsonDotNet.B, Tile","Key":"keyB"} 

请注意Newtonsoft文档中的这一注意事项:

当您的应用程序从外部源反序列化JSON时,应谨慎使用TypeNameHandling。 使用非None以外的值进行反序列化时,应使用自定义SerializationBindervalidation传入类型。

有关为什么需要这样做的讨论,请参阅Newtonsoft Json中的TypeNameHandling警告 , 如何配置Json.NET以创建易受攻击的Web API ,以及AlvaroMuñoz和Oleksandr Mirosh的黑帽纸https://www.blackhat.com/docs/ US-17 /周四/ US-17-穆尼奥斯-周五最的13 JSON-攻击,wp.pdf