使用 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<ISample>(stringA, settings);
b = JsonConvert.DeserializeObject<ISample>(stringB, settings);

我注意到,即使在设置 TypeNameHandling.Auto 时,序列化字符串中也不存在类型信息。但是,将"类型名称处理"设置为"对象"或"全部"有效。

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

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

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

类型 类型:系统型 要序列化的值的类型。当"类型名称处理"为"自动"时,使用此参数在值的类型不匹配时写出类型名称。指定类型是可选的。

在您的情况下,您将执行以下操作:

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 时,应谨慎使用类型名称处理。使用非 None 的值反序列化时,应使用自定义序列化绑定程序验证传入类型。

有关为什么可能需要这样做的讨论,请参阅 Newtonsoft Json 中的 TypeNameHandling 警告、如何配置 Json.NET 以创建易受攻击的 Web API 以及 Alvaro Muñoz & Oleksandr Mirosh 的黑帽论文 https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf

相关内容

  • 没有找到相关文章

最新更新