NewtonSoft.Json Serialize and Deserialize class with property of type IEnumerable<ISomeInterface>

AndyDBell picture AndyDBell · Aug 1, 2012 · Viewed 244.9k times · Source

I am trying to move some code to consume ASP.NET MVC Web API generated Json data instead of SOAP Xml.

I have run into a problem with serializing and deserializing properties of type:

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 serialize instances of SampleGroup easily with:

var sz = JsonConvert.SerializeObject( sampleGroupInstance );

However the corresponding deserialize fails:

JsonConvert.DeserializeObject<SampleGroup>( sz );

with this exception message:

"Could not create an instance of type JsonSerializationExample.ISample. Type is an interface or abstract class and cannot be instantated."

If I derive 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 deserialization problem but I cannot figure how to code the WriteJson method to get serialization working again.

Can anybody assist?

Is this a "correct" way to solve the problem in the first place?

Answer

cuongle picture cuongle · Aug 1, 2012

You don't need to use JsonConverterAttribute, keep your model clean, 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