Custom enum value name in System.Text.Json

June 23rd 2023 .NET Serialization

When serializing enums to JSON, it's usually better to serialize them as descriptive strings than incomprehensible magic numbers. Most of the time, it's good enough to simply use the names of enum members for this purpose. However, these must follow the rules for identifier names in C#, so they might be too restrictive if you need to use specific string values because of interoperability with other systems.

Newtonsoft Json.NET serializer allows you to use the EnumMember attribute in such cases:

[JsonConverter(typeof(StringEnumConverter))]
public enum SampleEnum
{
    ValueOne = 1,
    [EnumMember(Value = "Value Two")]
    ValueTwo = 2,
}

When this attribute is present on an enum member, its value will be used for serialization instead of the enum member name.

[Test]
public void NewtonsoftJsonReadsEnumMemberAttribute()
{
    var original = new SampleObject
    {
        Value = SampleEnum.ValueTwo,
    };

    var json = JsonConvert.SerializeObject(original);

    json.Should().Be("""{"Value":"Value Two"}""");
}

Unfortunately, the EnumMember attribute is ignored when using the new System.Text.Json serializer:

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum SampleEnum
{
    ValueOne = 1,
    [EnumMember(Value = "Value Two")]
    ValueTwo = 2,
}

[Test]
public void SystemTextJsonDoesNotReadEnumMemberAttribute()
{
    var original = new SampleObject
    {
        Value = SampleEnum.ValueTwo,
    };

    var json = JsonSerializer.Serialize(original);

    json.Should().Be("""{"Value":"ValueTwo"}""");
}

There's a GitHub issue with a long discussion about this missing feature which makes it clear that no built-in support is planned for it any time soon, if ever. However, I don't think that's much of an issue. The serializer is easily extendable, so you can write your own custom converter for this purpose. You can even find a working example with EnumMember attribute support in the same Github issue.

Or even better, use JsonStringEnumMemberConverter from the Macross.Json.Extensions NuGet package instead:

[JsonConverter(typeof(JsonStringEnumMemberConverter))]
public enum SampleEnum
{
    ValueOne = 1,
    [EnumMember(Value = "Value Two")]
    ValueTwo = 2,
}

[Test]
public void SystemTextJsonCustomConverterReadsEnumMemberAttribute()
{
    var original = new SampleObject
    {
        Value = SampleEnum.ValueTwo,
    };

    var json = JsonSerializer.Serialize(original);

    json.Should().Be("""{"Value":"Value Two"}""");
}

You can find a sample project with working JSON serialization using values from the EnumMember attribute in my GitHub repository. Feel free to try it out and play with it before implementing a similar solution in your own project.

There are quite a few Newtonsoft Json.NET features that are missing in System.Text.Json. Fortunately, most of these features can be added by using its extensibility model. Some of them are already implemented for you in the Macross.Json.Extensions NuGet package.

Get notified when a new blog post is published (usually every Friday):

If you're looking for online one-on-one mentorship on a related topic, you can find me on Codementor.
If you need a team of experienced software engineers to help you with a project, contact us at Razum.
Copyright
Creative Commons License