Serializing an Interface / Abstract Object Using NewtonSoft.JSON

One way to deserialize an interface and abstract properties is to use a class that sets TypeNameHandling to Auto during serialization and deserialization. However, when I try to do the same when serializing and deserializing the 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; } } 

The serialization and deserialization code is

 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, type information is not in the serialized string. However, the TypeNameHandling settings for Object or All work.

Did I miss something basic here?

+4
json c # serialization
source share
1 answer

To enable the 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 docs :

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

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

In your case, you will 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"} 

Note this caution from Newtonsoft Docs :

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

For a discussion of why this might be necessary, see TypeNameHandling caution in Newtonsoft Json , How to configure Json.NET to create a vulnerable web API , as well as Alvaro Munoz and Alexander Mirosh blackhat paper https://www.blackhat.com/docs /us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf p>

+5
source share

All Articles