反序列化接口和抽象属性的一种方法是通过在序列化和反序列化期间将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<ISample>(stringA, settings);
b = JsonConvert.DeserializeObject<ISample>(stringB, settings);
我注意到即使设置TypeNameHandling.Auto,序列化字符串中也不存在类型信息。但是,设置TypeNameHandling到Object或All有效。
我错过了一些基本的东西吗?
答案 0 :(得分:7)
要为$type
的多态对象启用TypeNameHandling.Auto
信息的输出,请使用以下重载:JsonConvert.SerializeObject Method (Object, Type, JsonSerializerSettings)
。来自docs:
public static string SerializeObject( Object value, Type type, JsonSerializerSettings settings )
型 键入: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 docs:
中的这一注意事项当您的应用程序从外部源反序列化JSON时,应谨慎使用TypeNameHandling。使用非None以外的值进行反序列化时,应使用自定义SerializationBinder验证传入类型。
有关为何需要这样做的讨论,请参阅TypeNameHandling caution in Newtonsoft Json,How to configure Json.NET to create a vulnerable web API和AlvaroMuñoz&amp; Oleksandr Mirosh的黑帽纸https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf