Search code examples
c#.net-corepolymorphismsystem.text.json.net-7.0

Polymorphic serialization for every child class in .NET 7 using System.Text.Json


In .NET 7, we can use JsonDerivedType to enable polymorphic serialization for a type:

[JsonDerivedType(typeof(ChildClass))]
public class BaseClass
{
    public string FirstName { get; set; }
}

public class ChildClass : BaseClass
{
    public string LastName { get; set; }
}

Suppose I want every class that derives from BaseClass to be polymorphically serializable. Is there a succinct way of doing this instead of having to type an annotation per class? Suppose I have dozens of derived types.


Solution

  • You can configure polymorphism with the contract model.

    From the documentation

    For use cases where attribute annotations are impractical or impossible

    In summary, you define a custom IJsonTypeInfoResolver and apply some reflection to define the polymorphism rules.

    Below example shows 2 hard coded types, but you can take it a step further by discovering the derived types via reflection (as long as you can also get the matching discriminator).

    public class CustomJsonTypeInfoResolver : DefaultJsonTypeInfoResolver
    {
        public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
        {
            JsonTypeInfo jsonTypeInfo = base.GetTypeInfo(type, options);
    
            Type baseType = typeof(YourBaseClass);
            if (jsonTypeInfo.Type == baseType)
            {
                jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions
                {
                    TypeDiscriminatorPropertyName = "$type" // Or any other of your choosing.
                    // Other code removed for brevity.
                    DerivedTypes =
                    {
                        new JsonDerivedType(typeof(DerivedType1), "discriminator1"),
                        new JsonDerivedType(typeof(DerivedType2), "discriminator2")
                    }
                    // Or use reflection to retrieve the derived types.
                };        
            }
            
             return jsonTypeInfo;
    }
    
    

    You need to set the TypeInfoResolver on the JsonSerializerOptions.

    Below code shows how to do so for an ASP.NET Core web application.

    builder.Services
        .AddControllers()
        .AddJsonOptions(options => options.JsonSerializerOptions.TypeInfoResolver = new CustomJsonTypeInfoResolver());