使用 NewtonSoft.JSON 序列化一个 interface/abstract 对象

Serializing an interface/abstract object using NewtonSoft.JSON

反序列化接口和抽象属性的一种方法是 class 是在序列化和反序列化期间将 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 有效。

我是不是漏掉了一些基本的东西?

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

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

type Type: System.Type The type of the value being serialized. This parameter is used when TypeNameHandling is Auto to write out the type name if the type of the value does not match. Specifing the type is optional.

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

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 中的警告:

TypeNameHandling should be used with caution when your application deserializes JSON from an external source. Incoming types should be validated with a custom SerializationBinder when deserializing with a value other than None.

有关为什么需要这样做的讨论,请参阅 , How to configure Json.NET to create a vulnerable web API, and Alvaro Muñoz & Oleksandr Mirosh's blackhat paper https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf