JSON.NET - how to deserialize an assembly of front-end instances?

I would like to serialize this code via json.net:

public interface ITestInterface { string Guid {get;set;} } public class TestClassThatImplementsTestInterface1 { public string Guid { get;set; } } public class TestClassThatImplementsTestInterface2 { public string Guid { get;set; } } public class ClassToSerializeViaJson { public ClassToSerializeViaJson() { this.CollectionToSerialize = new List<ITestInterface>(); this.CollectionToSerialize.add( new TestClassThatImplementsTestInterface2() ); this.CollectionToSerialize.add( new TestClassThatImplementsTestInterface2() ); } List<ITestInterface> CollectionToSerialize { get;set; } } 

I want to serialize / deserialize ClassToSerializeViaJson with json.net. Serialization works, but deserialization gives me this error:

Newtonsoft.Json.JsonSerializationException: Failed to create an instance of type ITestInterface. A type is an interface or abstract class and cannot be created.

So how can I deserialize the List<ITestInterface> collection?

+51
Apr 08 '13 at
source share
9 answers

Below is a complete working example with what you want to do:

 public interface ITestInterface { string Guid { get; set; } } public class TestClassThatImplementsTestInterface1 : ITestInterface { public string Guid { get; set; } public string Something1 { get; set; } } public class TestClassThatImplementsTestInterface2 : ITestInterface { public string Guid { get; set; } public string Something2 { get; set; } } public class ClassToSerializeViaJson { public ClassToSerializeViaJson() { this.CollectionToSerialize = new List<ITestInterface>(); } public List<ITestInterface> CollectionToSerialize { get; set; } } public class TypeNameSerializationBinder : SerializationBinder { public string TypeFormat { get; private set; } public TypeNameSerializationBinder(string typeFormat) { TypeFormat = typeFormat; } public override void BindToName(Type serializedType, out string assemblyName, out string typeName) { assemblyName = null; typeName = serializedType.Name; } public override Type BindToType(string assemblyName, string typeName) { var resolvedTypeName = string.Format(TypeFormat, typeName); return Type.GetType(resolvedTypeName, true); } } class Program { static void Main() { var binder = new TypeNameSerializationBinder("ConsoleApplication.{0}, ConsoleApplication"); var toserialize = new ClassToSerializeViaJson(); toserialize.CollectionToSerialize.Add( new TestClassThatImplementsTestInterface1() { Guid = Guid.NewGuid().ToString(), Something1 = "Some1" }); toserialize.CollectionToSerialize.Add( new TestClassThatImplementsTestInterface2() { Guid = Guid.NewGuid().ToString(), Something2 = "Some2" }); string json = JsonConvert.SerializeObject(toserialize, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Binder = binder }); var obj = JsonConvert.DeserializeObject<ClassToSerializeViaJson>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Binder = binder }); Console.ReadLine(); } } 
+34
Apr 08 '13 at 14:19
source share

I found this question trying to do it myself. After I implemented the answer of Peter Stapp (Garat) , I was amazed at how simple it seemed. If I just implemented a method that was already passed the exact type (as a string) that I wanted to create, why didn't the library bind it automatically?

In fact, I found that I did not need any custom folders, Json.Net could do exactly what I needed, provided that I said that this was what I was doing.

When serialized:

 string serializedJson = JsonConvert.SerializeObject(objectToSerialize, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple }); 

When deserializing:

 var deserializedObject = JsonConvert.DeserializeObject<ClassToSerializeViaJson>(serializedJson, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects }); 

Related documentation: serialization options for Json.NET and TypeNameHandling.

+79
Oct 31 '13 at 15:44
source share

I was also surprised at Garath's simplicity, and also came to the conclusion that the Json library can do this automatically. But I also thought it was even simpler than Ben Jenkinson's answer (although I see that it was modified by the json library developer himself). From my tests, all you have to do is set TypeNameHandling to Auto, for example:

 var objectToSerialize = new List<IFoo>(); // TODO: Add objects to list var jsonString = JsonConvert.SerializeObject(objectToSerialize, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); var deserializedObject = JsonConvert.DeserializeObject<List<IFoo>>(jsonString, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); 

From the documentation for the TypeNameHandling enumeration

Auto: include the name of the .NET type if the type of the serializable object does not match its declared type. Note that this does not include the default serialized root object.

+19
May 23 '15 at 12:30
source share

Using the default settings, you cannot. JSON.NET does not know how to deserialize an array. However, you can specify which type of converter to use for your interface type. To learn how to do this, see this page: http://blog.greatrexpectations.com/2012/08/30/deserializing-interface-properties-using-json-net/

You can also find information about this issue on this SO question: Casting interfaces for deserialization in JSON.NET

+7
Apr 08 '13 at 14:00
source share

This is an old question, but I thought I would add a more detailed answer (in the form of the article I wrote): http://skrift.io/articles/archive/bulletproof-interface-deserialization-in-jsonnet/

TL; DR: Instead of setting up Json.NET to embed type names in serialized JSON, you can use a JSON converter to figure out which class should be deserialized to use any custom logic.

This has the advantage that you can reorganize your types without worrying about breaking deserialization.

+4
May 6 '16 at 1:44
source share

Almost a duplicate of Inrego's answer, but it deserves further explanation:

If you use TypeNameHandling.Auto then it only includes the type / assembly name when required (e.g. interfaces and base / derived classes). This way your JSON is cleaner, smaller, more specific.

What is not one of the main selling points for XML / SOAP?

+3
Feb 24 '16 at 21:37
source share

I wanted to deserialize JSON that was not serialized by my application, so I needed to specify a specific implementation manually. I expanded Nicholas's answer.

Assume that

 public class Person { public ILocation Location { get;set; } } 

and concrete example

 public class Location: ILocation { public string Address1 { get; set; } // etc } 

Add to this class.

 public class ConfigConverter<I, T> : JsonConverter { public override bool CanWrite => false; public override bool CanRead => true; public override bool CanConvert(Type objectType) { return objectType == typeof(I); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new InvalidOperationException("Use default serialization."); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jsonObject = JObject.Load(reader); var deserialized = (T)Activator.CreateInstance(typeof(T)); serializer.Populate(jsonObject.CreateReader(), deserialized); return deserialized; } } 

Then define your interfaces with the JsonConverter attribute

 public class Person { [JsonConverter(typeof(ConfigConverter<ILocation, Location>))] public ILocation Location { get;set; } } 
+3
Feb 16 '17 at 6:18
source share

This can be done using the JSON.NET and JsonSubTypes attributes :

 [JsonConverter(typeof(JsonSubtypes))] [JsonSubtypes.KnownSubTypeWithProperty(typeof(Test1), "Something1")] [JsonSubtypes.KnownSubTypeWithProperty(typeof(Test2), "Something2")] public interface ITestInterface { string Guid { get; set; } } public class Test1 : ITestInterface { public string Guid { get; set; } public string Something1 { get; set; } } public class Test2 : ITestInterface { public string Guid { get; set; } public string Something2 { get; set; } } 

and just:

 var fromCode = new List<ITestInterface>(); // TODO: Add objects to list var json = JsonConvert.SerializeObject(fromCode); var fromJson = JsonConvert.DeserializeObject<List<ITestInterface>>(json); 
+2
Mar 11 '18 at 19:04
source share

Avoid using TypeNameHandling.Auto whenever possible, especially with user-controlled values.

You will need to write your own deserializer for the collection type .

Instead of repeating the others that have already published the converter code (in particular, Nicholas Westby , whose blog post was very useful and linked above ), I included the appropriate changes to deserialize the interface collection (I had an enum interface property to distinguish the developers):

  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { Collection<T> result = new Collection<T>(); var array = JArray.Load(reader); foreach (JObject jsonObject in array) { var rule = default(T); var value = jsonObject.Value<string>("MyDistinguisher"); MyEnum distinguisher; Enum.TryParse(value, out distinguisher); switch (distinguisher) { case MyEnum.Value1: rule = serializer.Deserialize<Type1>(jsonObject.CreateReader()); break; case MyEnum.Value2: rule = serializer.Deserialize<Type2>(jsonObject.CreateReader()); break; default: rule = serializer.Deserialize<Type3>(jsonObject.CreateReader()); break; } result.Add(rule); } return result; } 

Hope this is useful for the next person looking for an interface deserializer.

+1
Oct 12 '18 at 17:34
source share



All Articles