JSON
System.Text.Json
Badeend.EnumClass.SystemTextJson
is an auxiliary package that builds on System.Text.Json
s built-in support for polymorphism. Enabling this package automatically marks every enum class as [JsonPolymorphic]
and adds every enum case as a [JsonDerivedType]
.
Installation
dotnet add package Badeend.EnumClass.SystemTextJson
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;
}