'How to deserialize interfaces with Newtonsoft Json.Net

I have this class hierarchy :

public class ProxyBotsSnapshotLogEntryDetails : IBotsSnapshotLogEntryDetails
{
    public ICollection<IBotSnapshot> Snapshots { get; set; }
}
public class ProxyBotSnapshot : IBotSnapshot
{
    public string Name { get; set; }
    public ICollection<IBotSnapshotItem> States { get; set; }
}

public class ProxyBotSnapshotItem : IBotSnapshotItem
{
    public int Count { get; set; }
    public IrcBotChannelStateEnum State { get; set; }
}

and their corresponding interfaces

public interface IBotsSnapshotLogEntryDetails
{
    ICollection<IBotSnapshot> Snapshots { get; set; }
}

public interface IBotSnapshot
{
    string Name { get; set; }
    ICollection<IBotSnapshotItem> States { get; set; }
}

public interface IBotSnapshotItem
{
    int Count { get; set; }
    IrcBotChannelStateEnum State { get; set; }
}

that I would like to deserialize from JSON:

var test = JsonConvert.DeserializeObject<ProxyBotsSnapshotLogEntryDetails>(entry.DetailsSerialized);

but I get an error saying that Newtonsoft cannot convert interfaces.

I found this promising article:

https://www.c-sharpcorner.com/UploadFile/20c06b/deserializing-interface-properties-with-json-net/

but am not sure how to use the attribute, since in my case, the property is a list of interface.



Solution 1:[1]

Got it!

The converter provided in the article works super nicely, I was just missing the syntax to use it on a collection property. Here is the code with the converter and the working attributes:

// From the article
public class ConcreteConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType) => true;

    public override object ReadJson(JsonReader reader,
     Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize<T>(reader);
    }

    public override void WriteJson(JsonWriter writer,
        object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

public class ProxyBotsSnapshotLogEntryDetails : IBotsSnapshotLogEntryDetails
{
    [JsonProperty(ItemConverterType = typeof(ConcreteConverter<ProxyBotSnapshot>))]
    public ICollection<IBotSnapshot> Snapshots { get; set; }
}
public class ProxyBotSnapshot : IBotSnapshot
{
    public string Name { get; set; }

    [JsonProperty(ItemConverterType = typeof(ConcreteConverter<ProxyBotSnapshotItem>))]
    public ICollection<IBotSnapshotItem> States { get; set; }
}

public class ProxyBotSnapshotItem : IBotSnapshotItem
{
    public int Count { get; set; }
    public IrcBotChannelStateEnum State { get; set; }
}

Solution 2:[2]

Maybe it works if you add the following settings to the Serializer and Deserializer methods:

new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.Auto}

For example:

var test = JsonConvert.DeserializeObject<ProxyBotsSnapshotLogEntryDetails>(entry.DetailsSerialized,
 new JsonSerializerSettings 
{
  TypeNameHandling = TypeNameHandling.Auto
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bruno
Solution 2 Anno