Deserializing Interface Properties With Json.NET

The Newtonsoft.json Nuget package allows you to serialize and deserialize objects into JSON.

    Install-Package Newtonsoft.Json

In this article I will show you how to handle a scenario where your models are structured after interfaces and you need to implement them, but then you also need to know what the concrete type is to be able to deserialize your JSON.

Some basic operations from Newtonsoft.Json are:

You can convert an object to JSON using:

  1. JsonConvert.SerializeObject(main);   
And convert it back using:
  1. YourType x = JsonConvert.DeserializeObject<YourType>(json);   
It also supports dynamic objects:
  1. dynamic dyn = JsonConvert.DeserializeObject(json);    
  2. // dyn.Stuff   
These methods work just fine for concrete types. However if you have an interface in the middle you will get errors. For example, given the following structure:
  1. public interface IMainStuff    
  2. {    
  3.     ISubStuff SubStuff { getset; }    
  4. }    
  5. public interface ISubStuff    
  6. {    
  7.     string Name { getset; }    
  8. }    
  9.      
  10. public class MainStuff : IMainStuff    
  11. {    
  12.     public ISubStuff SubStuff { getset; }    
  13. }    
  14.      
  15. public class SubStuff : ISubStuff    
  16. {    
  17.     public string Name { getset; }    
  18. }  

If you attempt to deserialize MainStuff you will get the following exception:

  • An unhandled exception of type "Newtonsoft.Json.JsonSerializationException" occurred in Newtonsoft.Json.dll.
  • Additional information: Could not create an instance of type ConsoleApplication1.Program+ISubStuff. Type is an interface or abstract class and cannot be instantiated. Path "SubStuff.Name", line 1, position 20.

Json.NET does not know how to create the interface. If you want to handle it you need to implement a converter as in the following:

 

  1. public class ConcreteConverter<T> : JsonConverter    
  2. {    
  3.     public override bool CanConvert(Type objectType) => true;    
  4.      
  5.     public override object ReadJson(JsonReader reader,    
  6.      Type objectType, object existingValue, JsonSerializer serializer)    
  7.     {    
  8.         return serializer.Deserialize<T>(reader);    
  9.     }    
  10.      
  11.     public override void WriteJson(JsonWriter writer,    
  12.         object value, JsonSerializer serializer)    
  13.     {    
  14.         serializer.Serialize(writer, value);    
  15.     }    
  16. }    
And then tell your concrete class how to handle the interface property by annotating it with the converter information.
  1. public class MainStuff : IMainStuff    
  2. {    
  3.     [JsonConverter(typeof(ConcreteConverter<SubStuff>))]    
  4.     public ISubStuff SubStuff { getset; }    
  5. }  
code