Using Json.NET converters to deserialize properties

Viewed 107622

I have a class definition that contains a property that returns an interface.

public class Foo
{ 
    public int Number { get; set; }

    public ISomething Thing { get; set; }
}

Attempting to serialize the Foo class using Json.NET gives me an error message like, "Could not create an instance of type 'ISomething'. ISomething may be an interface or abstract class."

Is there a Json.NET attribute or converter that would let me specify a concrete Something class to use during deserialization?

9 Answers

One of the things you can do with Json.NET is:

var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Objects;

JsonConvert.SerializeObject(entity, Formatting.Indented, settings);

The TypeNameHandling flag will add a $type property to the JSON, which allows Json.NET to know which concrete type it needs to deserialize the object into. This allows you to deserialize an object while still fulfilling an interface or abstract base class.

The downside, however, is that this is very Json.NET-specific. The $type will be a fully-qualified type, so if you're serializing it with type info,, the deserializer needs to be able to understand it as well.

Documentation: Serialization Settings with Json.NET

I've wondered this same thing, but I'm afraid it can't be done.

Let's look at it this way. You hand to JSon.net a string of data, and a type to deserialize into. What is JSON.net to do when it hit's that ISomething? It can't create a new type of ISomething because ISomething is not an object. It also can't create an object that implements ISomething, since it doesn't have a clue which of the many objects that may inherit ISomething it should use. Interfaces, are something that can be automatically serialized, but not automatically deserialized.

What I would do would be to look at replacing ISomething with a base class. Using that you might be able to get the effect you are looking for.

Here is a reference to an article written by ScottGu

Based on that, I wrote some code which I think might be helpful

public interface IEducationalInstitute
{
    string Name
    {
        get; set;
    }

}

public class School : IEducationalInstitute
{
    private string name;
    #region IEducationalInstitute Members

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    #endregion
}

public class Student 
{
    public IEducationalInstitute LocalSchool { get; set; }

    public int ID { get; set; }
}

public static class JSONHelper
{
    public static string ToJSON(this object obj)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        return serializer.Serialize(obj);
    }
    public  static string ToJSON(this object obj, int depth)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        serializer.RecursionLimit = depth;
        return serializer.Serialize(obj);
    }
}

And this is how you would call it

School myFavSchool = new School() { Name = "JFK High School" };
Student sam = new Student()
{
    ID = 1,
    LocalSchool = myFavSchool
};
string jSONstring = sam.ToJSON();

Console.WriteLine(jSONstring);
//Result {"LocalSchool":{"Name":"JFK High School"},"ID":1}

If I understand it correctly, I do not think you need to specify a concrete class which implements the interface for JSON serialization.

Related