Class NewtonSoft.Json Serialize and Deserialize with property of type IEnumerable <ISomeInterface>
I am trying to move some code to use the ASP.NET MVC Web API generated by Json data instead of SOAP Xml.
I had a problem with serializing and deserializing type properties:
IEnumerable<ISomeInterface>. Here is a simple example:
public interface ISample{ int SampleId { get; set; } } public class Sample : ISample{ public int SampleId { get; set; } } public class SampleGroup{ public int GroupId { get; set; } public IEnumerable<ISample> Samples { get; set; } } } I can easily serialize SampleGroup instances with:
var sz = JsonConvert.SerializeObject( sampleGroupInstance ); However, the corresponding deserialization is not performed:
JsonConvert.DeserializeObject<SampleGroup>( sz ); with this exception message:
"Cannot create an instance of type JsonSerializationExample.ISample. The type is an interface or abstract class and cannot be created."
If I get a JsonConverter, I can decorate my property as follows:
[JsonConverter( typeof (SamplesJsonConverter) )] public IEnumerable<ISample> Samples { get; set; } Here is the JsonConverter:
public class SamplesJsonConverter : JsonConverter{ public override bool CanConvert( Type objectType ){ return ( objectType == typeof (IEnumerable<ISample>) ); } public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ){ var jA = JArray.Load( reader ); return jA.Select( jl => serializer.Deserialize<Sample>( new JTokenReader( jl ) ) ).Cast<ISample>( ).ToList( ); } public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ){ ... What works here? } } This converter solves the problem of deserialization, but I cannot figure out how to code the WriteJson method to serialize again.
Can anyone help?
Is this the "right" way to solve the problem in the first place?
You do not need to use JsonConverterAttribute , keep your model clean, and also use CustomCreationConverter , the code is simpler:
public class SampleConverter : CustomCreationConverter<ISample> { public override ISample Create(Type objectType) { return new Sample(); } } Then:
var sz = JsonConvert.SerializeObject( sampleGroupInstance ); JsonConvert.DeserializeObject<SampleGroup>( sz, new SampleConverter()); Documentation: Deserialize with CustomCreationConverter

This is pretty simple and free json.net support, you just need to use the following JsonSettings when serializing and deserializing:
JsonConvert.SerializeObject(graph,Formatting.None, new JsonSerializerSettings() { TypeNameHandling =TypeNameHandling.Objects, TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple }); and for Deserialzing use the code below:
JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bData),type, new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.Objects} ); Just pay attention to the JsonSerializerSettings object initializer, which is important to you.
I solved this problem using a special parameter for JsonSerializerSettings called TypeNameHandling.All
The TypeNameHandling parameter includes type information for JSON serialization and read type information to create creation types during JSON deserialization
Serialization:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; var text = JsonConvert.SerializeObject(configuration, settings); Deserialization:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; var configuration = JsonConvert.DeserializeObject<YourClass>(json, settings); The YourClass class can have any type of base type, and it will be correctly serialized.
Great solution, thanks! I took the AndyDBell question and Cuong Le answer to build an example with two interface options:
public interface ISample { int SampleId { get; set; } } public class Sample1 : ISample { public int SampleId { get; set; } public Sample1() { } } public class Sample2 : ISample { public int SampleId { get; set; } public String SampleName { get; set; } public Sample2() { } } public class SampleGroup { public int GroupId { get; set; } public IEnumerable<ISample> Samples { get; set; } } class Program { static void Main(string[] args) { //Sample1 instance var sz = "{\"GroupId\":1,\"Samples\":[{\"SampleId\":1},{\"SampleId\":2}]}"; var j = JsonConvert.DeserializeObject<SampleGroup>(sz, new SampleConverter<Sample1>()); foreach (var item in j.Samples) { Console.WriteLine("id:{0}", item.SampleId); } //Sample2 instance var sz2 = "{\"GroupId\":1,\"Samples\":[{\"SampleId\":1, \"SampleName\":\"Test1\"},{\"SampleId\":2, \"SampleName\":\"Test2\"}]}"; var j2 = JsonConvert.DeserializeObject<SampleGroup>(sz2, new SampleConverter<Sample2>()); //Print to show that the unboxing to Sample2 preserved the SampleName values foreach (var item in j2.Samples) { Console.WriteLine("id:{0} name:{1}", item.SampleId, (item as Sample2).SampleName); } Console.ReadKey(); } } And the general version for SampleConverter:
public class SampleConverter<T> : CustomCreationConverter<ISample> where T: new () { public override ISample Create(Type objectType) { return ((ISample)new T()); } } In my projects, this part of the code always worked as the default serializer, which serializes the specified value, as if there was no special converter:
serializer.Serialize(writer, value); I got this to work:
explicit conversion
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jsonObj = serializer.Deserialize<List<SomeObject>>(reader); var conversion = jsonObj.ConvertAll((x) => x as ISomeObject); return conversion; } After that:
public interface ITerm { string Name { get; } } public class Value : ITerm... public class Variable : ITerm... public class Query { public IList<ITerm> Terms { get; } ... } I managed to convert a trick implementing this:
public class TermConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var field = value.GetType().Name; writer.WriteStartObject(); writer.WritePropertyName(field); writer.WriteValue((value as ITerm)?.Name); writer.WriteEndObject(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jsonObject = JObject.Load(reader); var properties = jsonObject.Properties().ToList(); var value = (string) properties[0].Value; return properties[0].Name.Equals("Value") ? (ITerm) new Value(value) : new Variable(value); } public override bool CanConvert(Type objectType) { return typeof (ITerm) == objectType || typeof (Value) == objectType || typeof (Variable) == objectType; } } This allows me to serialize and deserialize to JSON, for example:
string JsonQuery = "{\"Terms\":[{\"Value\":\"This is \"},{\"Variable\":\"X\"},{\"Value\":\"!\"}]}"; ... var query = new Query(new Value("This is "), new Variable("X"), new Value("!")); var serializeObject = JsonConvert.SerializeObject(query, new TermConverter()); Assert.AreEqual(JsonQuery, serializeObject); ... var queryDeserialized = JsonConvert.DeserializeObject<Query>(JsonQuery, new TermConverter());