Search code examples
json.net-core-3.0system.text.json

Serialize objects implementing interface with System.Text.Json


I have a master class which contains a generic collection. Elements in the collection are of diffetent types, and each implements an interface.

Master class:

public class MasterClass
{
    public ICollection<IElement> ElementCollection { get; set; }
}

Contract for the elements:

public interface IElement
{
    string Key { get; set; }
}

Two samples for the elements:

public class ElementA : IElement
{
    public string Key { get; set; }

    public string AValue { get; set; }
}

public class ElementB : IElement
{
    public string Key { get; set; }

    public string BValue { get; set; }
}

I need to serialize an instance of MasterClass object using the new System.Text.Json library in Json. Using the following code,

public string Serialize(MasterClass masterClass)
{
    var options = new JsonSerializerOptions
    {
        WriteIndented = true,
    };
    return JsonSerializer.Serialize(masterClass, options);
}

I get the follwing JSON:

{
    "ElementCollection":
    [
        {
            "Key": "myElementAKey1"
        },
        {
            "Key": "myElementAKey2"
        },
        {
            "Key": "myElementBKey1"
        }
    ]
}

instead of:

{
    "ElementCollection":
    [
        {
            "Key": "myElementAKey1",
            "AValue": "MyValueA-1"
        },
        {
            "Key": "myElementAKey2",
            "AValue": "MyValueA-2"
        },
        {
            "Key": "myElementBKey1",
            "AValue": "MyValueB-1"
        }
    ]
}

Which class (converter, writer, ...)should I implement to obtain the complete JSON ?

Thanks in advance for your help.


Solution

  • The solution is to implement a generic converter (System.Text.Json.Serialization.JsonConverter) :

    public class ElementConverter : JsonConverter<IElement>
    {
        public override IElement Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }
    
        public override void Write(Utf8JsonWriter writer, IElement value, JsonSerializerOptions options)
        {
            if (value is ElementA)
                JsonSerializer.Serialize(writer, value as ElementA, typeof(ElementA), options);
            else if (value is ElementB)
                JsonSerializer.Serialize(writer, value as ElementB, typeof(ElementB), options);
            else
                throw new ArgumentOutOfRangeException(nameof(value), $"Unknown implementation of the interface {nameof(IElement)} for the parameter {nameof(value)}. Unknown implementation: {value?.GetType().Name}");
        }
    }
    

    This just needs some more work for the Read method.