System.Text.Json
extensions.
- Supports any attribute for enum member serialization.
- Provides option for using your own custom serializer implementation for enum members.
- and much more...
The motivation behind this project is to extend System.Text.Json
features.
You can download the package from nuget.org.
You can find the release notes here.
This library comes with the following features.
This library can make use of an implementation of this base class provided by the EgonsoftHU.Extensions.Bcl
(>= 3.0.0
) nuget package.
It has a static Current
property that can be set to your custom implementation.
By default, the Current
property is set to a default implementation that supports the following attribute:
System.Runtime.Serialization.EnumMemberAttribute
Converting / retrieving an enum member value to / from a string uses these values in the following order, from highest to lowest priority:
- The value of the
EnumMemberAttribute.Value
property, if that attribute is applied to the current enum member.- Both reading and writing are case sensitive.
- The name of the enum member.
- Reading is case insensitive.
- Writing is case sensitive.
Please note:
The base class makes use of the EgonsoftHU.Extensions.Bcl.Enumerations.EnumInfo<TEnum>
type.
When accessing a specific EnumInfo<TEnum>
type then its SerializedValue
instance property
will be initialized by the current serializer set in the EnumValueSerializer.Current
property;
therefore, it is highly recommended to set that property to the same implementation you will use
for configuring JSON serializer options.
This is an implementation of the above mentioned EgonsoftHU.Extensions.Bcl.Enumerations.Serialization.EnumValueSerializer
type and
it supports attributes and System.Text.Json.JsonNamingPolicy
to convert/retrieve enum member values to/from a string.
The following attributes are supported:
System.Text.Json.Serialization.JsonStringEnumMemberNameAttribute
(available inSystem.Text.Json
(>= 9.0.0
))System.Runtime.Serialization.EnumMemberAttribute
System.ComponentModel.DescriptionAttribute
System.ComponentModel.DisplayNameAttribute
System.ComponentModel.DataAnnotations.DisplayAttribute
(Description
,Name
andShortName
properties are supported.)
To create an instance and select an attribute using the EgonsoftHU.Text.Json.Serialization.EnumMemberNameSelectorOption
enum type:
using System.Text.Json;
using EgonsoftHU.Text.Json.Serialization;
using EgonsoftHU.Text.Json.Serialization.Converters;
var serializer =
new JsonEnumValueSerializer(
JsonNamingPolicy.CamelCase,
// The second parameter is optional. This is the default value:
EnumMemberNameSelectorOption.UseJsonStringEnumMemberNameAttribute
);
Converting / retrieving an enum member value to / from a string uses these values in the following order, from highest to lowest priority:
- The value of the selected attribute, if that attribute is applied to the current enum member.
- Both reading and writing are case sensitive.
- The value produced by the specified
JsonNamingPolicy
.- Both reading and writing are case sensitive.
- The name of the enum member.
- Reading is case insensitive.
- Writing is case sensitive.
You can create and use your own EnumValueSerializer
implementation if the above mentioned
JsonEnumValueSerializer
implementation does not fit your needs.
Additionally, you can use the EnumInfo<TEnum>.Attributes
instance property to access all the
attributes that are applied to an enum member.
This is an implementation of the System.Text.Json.Serialization.JsonConverterFactory
that you can add to the
System.Text.Json.JsonSerializerOptions.Converters
collection.
You can specify
- a
JsonNamingPolicy
- a factory delegate to create an instance of an implementation of the
EnumValueSerializer
type using an instance ofJsonSerializerOptions
and an instance ofJsonNamingPolicy
.
This is a static class that provides
- read-only default (
Default
,DefaultWriteIndented
) properties and - a writable current (
Current
) property
to hold instances of the System.Text.Json.JsonSerializerOptions
type.
The default instance is created this way:
// EgonsoftHU namespaces are displayed only for clarity.
var defaultEnumValueSerializer =
new EgonsoftHU.Text.Json.Serialization.Converters.JsonEnumValueSerializer(JsonNamingPolicy.CamelCase);
EgonsoftHU.Extensions.Bcl.Enumerations.Serialization.EnumValueSerializer.Current = defaultEnumValueSerializer;
JsonSerializerOptions options =
new(JsonSerializerDefaults.Web)
{
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
WriteIndented = false
};
options.Converters.Add(
new EgonsoftHU.Text.Json.Serialization.JsonStringEnumConverter(
JsonNamingPolicy.CamelCase,
enumValueSerializerFactory: (jsonSerializerOptions, jsonNamingPolicy) => defaultEnumValueSerializer
)
);
Suppose you already have an existing instance of the JsonSerializerOptions
class that you would like to use when configuring ASP.NET Core.
This CopyTo()
extension method comes in handy in this case:
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder(args);
JsonSerializerOptions options = /* your already existing instance */;
builder
.Services
.AddControllers()
// source.CopyTo(target) will override target's settings with the source's settings.
.AddJsonOptions(jsonOptions => options.CopyTo(jsonOptions.JsonSerializerOptions));
Although these are not the most wanted naming policies, they are available in case you need them.
EgonsoftHU.Text.Json.JsonUpperCaseNamingPolicy
EgonsoftHU.Text.Json.JsonLowerCaseNamingPolicy
In this example configuration converting / retrieving an enum member value to / from a string will use these values in the following order, from highest to lowest priority:
JsonStringEnumMemberNameAttribute.Name
, if that attribute is applied to the current enum member.- Both reading and writing are case sensitive.
- The value produced by
JsonNamingPolicy.CamelCase
.- Both reading and writing are case sensitive.
- The name of the enum member.
- Reading is case insensitive.
- Writing is case sensitive.
using System.Text.Json;
using EgonsoftHU.Text.Json.Serialization;
using EgonsoftHU.Text.Json.Serialization.Converters;
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder(args);
JsonSerializerOptions options =
new(JsonSerializerDefaults.Web)
{
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
WriteIndented = false
};
options.Converters.Add(
new JsonStringEnumConverter(
JsonNamingPolicy.CamelCase
// If omitting the delegate factory then
// the value of the EnumValueSerializer.Current property will be used.
)
);
EnumValueSerializer.Current = new JsonEnumValueSerializer(JsonNamingPolicy.CamelCase);
JsonSerializerOptionsProvider.Current = options;
builder
.Services
.AddControllers()
.AddJsonOptions(jsonOptions => options.CopyTo(jsonOptions.JsonSerializerOptions));
It already includes the newer (but not stable) 9.0.0
version of System.Text.Json
nuget package
that contains this attribute.
So this package - since it targets net9.0
as well - directly uses this attribute type.
For target frameworks other than net9.0
currently this package references the latest stable
(8.0.5
) version of the System.Text.Json
nuget package that does not contain this attribute.
It means that in this case the JsonEnumValueSerializer
checks for this attribute by name and uses
reflection to get the value of its Name
property.
This package will be updated to use the 9.0.0
version of the System.Text.Json
nuget package
as soon as a stable version of it is available.
Since the JsonEnumValueSerializer
can check for this attribute by name you can start using
(or migrate to) this attribute without the need to reference the newer (but not stable)
9.0.0
version of System.Text.Json
nuget package.
All you need to do is to create an attribute with the same name (JsonStringEnumMemberNameAttribute
)
within the same namespace (System.Text.Json.Serialization
) in your project.
You can find the source code for this attribute here:
JsonStringEnumMemberNameAttribute
Please note:
For this workaround to work neither the copy of the attribute nor the enum types using that copy
should be in an assembly that references the 9.0.0
version of the System.Text.Json
nuget package.
Otherwise, you will get either a
CS0436 compiler warning or a
CS0433 compiler error.
Important:
System.Text.Json
will not target net6.0
starting with version 9.0.0
which means
that the net6.0
version of this package will keep using the 8.0.5
version of it,
hence you can keep your copy of the attribute in this case.
To be on the safe side you also need to set a switch at application startup so that
the JsonEnumValueSerializer
will check for this attribute always by name
even if you upgrade to the 9.0.0
version of the System.Text.Json
nuget package.
Option #1 - Set the switch in the code at application startup
using System;
using EgonsoftHU.Text.Json.Constants;
AppContext.SetSwitch(AppContextSwitches.AlwaysCheckForJsonStringEnumMemberAttributeByName, true);
Option #2 - Set the switch in the startup project's .csproj file (in case of an SDK-style project)
<Project Sdk="Microsoft.NET.Sdk">
<!-- Rest is omitted for clarity -->
<ItemGroup>
<RuntimeHostConfigurationOption
Include="Switch.EgonsoftHU.Text.Json.AlwaysCheckForJsonStringEnumMemberAttributeByName"
Value="true"
/>
</ItemGroup>
</Project>
Option #3 - Set the switch in the startup project's App.config file (in case of a classic .NET Framework project)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- Rest is omitted for clarity -->
<runtime>
<AppContextSwitchOverrides
value="Switch.EgonsoftHU.Text.Json.AlwaysCheckForJsonStringEnumMemberAttributeByName=true"
/>
</runtime>
</configuration>
Please note:
Before removing this switch after upgrading to the 9.0.0
version of the System.Text.Json
nuget package,
make sure you deleted your copy of the attribute and your enum types reference the original attribute.