Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 840
Bruno Avatar asked May 30 '18 21:05

Bruno


People also ask

Can you deserialize Interface C#?

Short answer: no. Deserialization involves creating an instance, and you can't create instances of interfaces.

How does Newtonsoft JSON deserialize work?

Newtonsoft. Json uses reflection to get constructor parameters and then tries to find closest match by name of these constructor parameters to object's properties. It also checks type of property and parameters to match. If there is no match found, then default value will be passed to this parameterized constructor.

Is Newtonsoft JSON obsolete?

Yet Newtonsoft. Json was basically scrapped by Microsoft with the coming of . NET Core 3.0 in favor of its newer offering designed for better performance, System.


1 Answers

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; }
}
like image 112
Bruno Avatar answered Nov 10 '22 14:11

Bruno