Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
479 views
in Technique[技术] by (71.8m points)

c# - Serializing an interface/abstract object using NewtonSoft.JSON

One way of deserializing interface and abstract properties is a class is by setting TypeNameHandling to Auto during serialization and deserialization. However, when I try the same when serializing and deserializing an interface object directly, it does not work -

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;
    }
}

Serialization and deserialization code -

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);

I noticed that even when setting TypeNameHandling.Auto the type information is not present in the serialized string. However, settings TypeNameHandling to Object or All works.

Am I missing something basic here?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To enable output of $type information at the root level for a polymorphic object with TypeNameHandling.Auto, use the following overload: 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.

In your case, you would do:

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

Console.WriteLine(stringA);
Console.WriteLine(stringB);

And get the result:

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

Do take note of this caution from the 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.

For a discussion of why this may be necessary, see TypeNameHandling caution in Newtonsoft Json, 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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...