2

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.

pfx
  • 20,323
  • 43
  • 37
  • 57
user246392
  • 2,661
  • 11
  • 54
  • 96

1 Answers1

1

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());
pfx
  • 20,323
  • 43
  • 37
  • 57
  • how would you get the reflection to work? I continue to receive this error: `CS0200: Property or indexer 'JsonPolymorphismOptions.DerivedTypes' cannot be assigned to -- it is read only` – G684 Jul 29 '23 at 21:03
  • @G684 I don't know your code, but notice that there's no `new` used in the initialization of the `DerivedTypes`. Behind the scenes, the items used in the initialization get assiged to the `DerivedTypes` via an `Add` statement. See [object Initializers with collection read-only property initialization](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#object-initializers-with-collection-read-only-property-initialization). – pfx Jul 30 '23 at 12:49