30 March 2015 JSON, JSON.NET Robert Muehsig

Base Class & Implementations

public abstract class BaseFoo
{
    public string FooBarBuzz { get; set; }
}

public class AFoo : BaseFoo
{
    public string A { get; set; }
}

public class BFoo : BaseFoo
{
    public string B { get; set; }
}

When we deserilize it we need somehow a “marker”-property and I use the “FooBarBuzz” property from the BaseFoo-class as my marker. If it contains “A”, then it is implementation “AFoo” and “B” for “BFoo”.

Serialize

The serialization part works as expected:

AFoo a = new AFoo();
a.FooBarBuzz = "A";
a.A = "Hello World";

BFoo b = new BFoo();
b.FooBarBuzz = "B";
b.B = "Hello World";

List<BaseFoo> allFoos = new List<BaseFoo>();
allFoos.Add(a);
allFoos.Add(b);

var result = JsonConvert.SerializeObject(allFoos);

Resulting Json:

x

Deserialize and boom…

If we continue now and just use the typical code we get a nice exception:

var test = JsonConvert.DeserializeObject<List<BaseFoo>>(result);

Exception:

Additional information: Could not create an instance of type ConsoleApplication6.BaseFoo. Type is an interface or abstract class and cannot be instantiated. Path ‘[0].A’, line 1, position 6.

Introducing a simple JsonConverter

The exception is pretty clear, because JSON.NET has no knowledge about our convention. The way to go* is to write a JsonConverter. I found a couple of implementations on StackOverflow, but this one seems to be the easiest and best option.

* Small Update based on the comment from Michael: JSON.NET can also include the TypeName in the JSON as a “$type” property. If this is not an issue for you, then just add the “TypeNameHandling.Auto” to the JsonSerializerSettings and it will work. In my actual scenario I want a clean JSON output, without JSON.NET magic. That’s the reason for the converter.

public class FooConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(BaseFoo));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        if (jo["FooBarBuzz"].Value<string>() == "A")
            return jo.ToObject<AFoo>(serializer);

        if (jo["FooBarBuzz"].Value<string>() == "B")
            return jo.ToObject<BFoo>(serializer);

        return null;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

When we read the JSON we look for our “FooBarBuzz”-property and serialize it to the correct implementation.

Let’s use our new JsonConverter

Just create a new instance of the Converter and apply it to the DeserializeObject method and you are done.

JsonConverter[] converters = { new FooConverter()};
var test = JsonConvert.DeserializeObject<List<BaseFoo>>(result, new JsonSerializerSettings() { Converters = converters });

Easy, right?

The full sample can be viewed on GitHub


Written by Robert Muehsig

Software Developer - from Dresden, Germany, now living & working in Switzerland. Microsoft MVP & Web Geek.
Other Projects: ExpensiveMeeting | EinKofferVollerReisen.de


blog comments powered by Disqus