bx

Deserializing Child Interface with Json.NET

Problem

When I was recently trying to deserialize some json to a type that contained an interface, I encountered this error:

Could not create an instance of type Foo. Type is an interface or abstract class and cannot be instantiated. Path ‘Bar’

I sat there for a few seconds scratching my head, when it dawned on me that of course it could not deserialize. Firstly because you can’t create a new instance of an interface however hard you tried, so how was I expecting Json.NET to. Secondly Json.NET had no idea what type to actually define it as…

Solution

So my investigation began and I discovered CustomCreationConverter which allows you to define how you want a specified type to be converted by Json.NET.

public class ResultDataConverter : CustomCreationConverter<IResultData>
{
    public Type ResultDataType { get; private set; }

    public ResultDataConverter(Type reportDataType)
    {
        // Sets the strong type for IResultData
        ResultDataType = reportDataType;
    }

    public override IResultData Create(Type objectType)
    {
        // Converts the anonymouse IResultData to the strong type defined in the constructor
        return (IResultData)Activator.CreateInstance(ResultDataType);
    }
}

When I initialize the converter I specify how the interface will be handled.

var converter = new ResultDataConverter(typeof(ResultData));

var deseralizeSettings = new JsonSerializerSettings();
deseralizeSettings.Converters.Add(converter);

var results = JsonConvert.DeserializeObject<ResultWrapper>(json, deseralizeSettings);

I’ve committed the sample code and some unit tests to github.

Caveat

This approach worked great for me because I was consuming json from an API and the type was always the same depending on which API I called. If you need the interface to deserialize different types, this approach probably wont work for you.

If you have control over how your json is returned, then I would suggest trying to include the definition of the type within it. This means there would be an extra $type property against each object in the json.

...
'ResultType': [{
    '$type': 'Foo.Bar.FoodResultType, Foo.Bar',
    'Id': '1',
    ...
}, {
    '$type': 'Foo.Bar.DrinkResultType, Foo.Bar',
    'Id': '1',
    ...
}

This link provides some better details. SerializeTypeNameHandling

⇺ back