Table of Contents

JSON

System.Text.Json

Badeend.EnumClass.SystemTextJson is an auxiliary package that builds on System.Text.Jsons built-in support for polymorphism. Enabling this package automatically marks every enum class as [JsonPolymorphic] and adds every enum case as a [JsonDerivedType].

Installation

NuGet Badeend.EnumClass.SystemTextJson

dotnet add package Badeend.EnumClass.SystemTextJson

API documentation →

Configure standalone JsonSerializerOptions

using Badeend.EnumClass.SystemTextJson;

var options = new JsonSerializerOptions();

options.AddEnumClasses(); // <--- HERE

var _ = JsonSerializer.Serialize(myObj, options);

Configure ASP.NET Core

Depending on which parts of ASP.NET Core you use, you might need to configure it twice:

using Badeend.EnumClass.SystemTextJson;

builder.Services.Configure<Microsoft.AspNetCore.Mvc.JsonOptions>(options =>
{
    options.JsonSerializerOptions.AddEnumClasses(); // <--- HERE
});

// And/or:

builder.Services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(options =>
{
    options.SerializerOptions.AddEnumClasses(); // <--- HERE
});

Customization

Discriminator values

Given the following enum:

[EnumClass]
public abstract record Shape
{
    public record BigCircle(float Radius) : Shape;
}
Default

By default, the type name of the enum case are used as discriminator value:

{
    "$type": "BigCircle",
    "Radius": 3.14
}
DiscriminatorNamingPolicy

When calling .AddEnumClasses() you can optionally pass a JsonNamingPolicy to alter the default naming scheme. For example:

options.AddEnumClasses(new() { DiscriminatorNamingPolicy = JsonNamingPolicy.KebabCaseLower });
{
    "$type": "big-circle",
    "Radius": 3.14
}
[JsonDiscriminator]

Alternatively, you can override the defaults by annotating the discriminator on a case-by-case basis:

using Badeend.EnumClass.SystemTextJson;

[EnumClass]
public abstract record Shape
{
    [JsonDiscriminator("ROUND")]
    public record BigCircle(float Radius) : Shape;
}
{
    "$type": "ROUND",
    "Radius": 3.14
}

Discriminator property name

By default, System.Text.Json uses $type as the discriminator property name. You can still use the [JsonPolymorphic] attribute to configure this (and other) settings. For example:

[EnumClass]
[JsonPolymorphic(TypeDiscriminatorPropertyName = "my-type")]
public abstract class MyEnum
{
    // ...
}

Complete control

If an enum class declares any [JsonDerivedType] attribute, this package backs off completely and won't perform any automatic registration. It is then back up to you to register the subtypes you want to be serializable:

[EnumClass]
[JsonPolymorphic]
[JsonDerivedType(typeof(Shape.BigCircle), "Circle")]
public abstract record Shape
{
    public record Circle(float Radius) : Shape;

    public record SecretRectangle(float Width, float Height) : Shape;
}