skip to Main Content

I’m trying to create a Client library that will allow users to push serialized data to a service.

so I created a class

public class Data
{
   public string Prop1 {get; set;}
   public SubData Prop2 {get; set;}
}

public abstract class SubData
{
   public string Prop3 {get; set;}
}

I would like to allow users to extend that SubData to add custom properties. but I’m having issues in my Serialization, it doesn’t serialize the properties of the extended inner object

JsonSerializer.Serialize(data) 

I know that I could decorate my SubData class with JsonDerivedType attribute, but my problem is that SubData is in a package, and it doesn’t know about who will extend it and with what (and it doesn’t care)

I don’t know if I’m clear what my problem is so here is a full test to replicate:

using System.Text.Json;

public class Data
{
    public string Prop1 { get; set; }
    public SubData SubData { get; set; }
}

public abstract class SubData
{
    public string Prop2 { get; set; }
}

public class ExtendedSubData : SubData
{
    public string Prop3 { get; set; }

}

var data = new Data
{
    Prop1 = "1",
    SubData = new ExtendedSubData
    {
        Prop2 = "2",
        Prop3 = "3"
    }
};

SerializData(data);

void SerializData(Data data)
{
    var serialized = JsonSerializer.Serialize<object>(data);
    // serialized at this point doesn't contain Prop3 of 
    // ExtendedSubData
}

2

Answers


  1. The issue you’re facing is that the JsonSerializer doesn’t know about the existence of ExtendedSubData and its additional properties because it’s not explicitly referenced in the serialization process

    using System;
    using System.Text.Json;
    using System.Text.Json.Serialization;
    
    public class Data
    {
        public string Prop1 { get; set; }
        public SubData SubData { get; set; }
    }
    
    public abstract class SubData
    {
        public string Prop2 { get; set; }
    }
    
    public class ExtendedSubData : SubData
    {
        public string Prop3 { get; set; }
    }
    
    public class SubDataConverter : JsonConverter<SubData>
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return typeof(SubData).IsAssignableFrom(typeToConvert);
        }
    
        public override SubData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }
    
        public override void Write(Utf8JsonWriter writer, SubData value, JsonSerializerOptions options)
        {
            JsonSerializer.Serialize(writer, value, value.GetType(), options);
        }
    }
    
    var data = new Data
    {
        Prop1 = "1",
        SubData = new ExtendedSubData
        {
            Prop2 = "2",
            Prop3 = "3"
        }
    };
    
    var options = new JsonSerializerOptions();
    options.Converters.Add(new SubDataConverter());
    
    var serialized = JsonSerializer.Serialize(data, options);
    Console.WriteLine(serialized);
    
    Login or Signup to reply.
  2. As an alternative to the custom JsonConverter, you can replace the SubData property with generic

    public class Data<TSubData>
        where TSubData : SubData
    {
        public string Prop1 { get; set; }
        public TSubData SubData { get; set; }
    }
    
    string SerializData<TSubData>(Data<TSubData> data)
        where TSubData : SubData
    {
        return JsonSerializer.Serialize<object>(data);
    }
    

    Test it on dotnetfiddle:
    https://dotnetfiddle.net/lkOM0Z

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search