Search code examples
c#enumssystem.text.json.net-8.0native-aot

How to enable JsonStringEnumConverter for all enums in .NET AOT


It looks like JsonStringEnumConverter requires dynamic code and we should switch to JsonStringEnumConverter<T> in AOT.

[JsonConverter(typeof(JsonStringEnumConverter<MyEnum>))]
public enum MyEnum { Foo, Bar }

[JsonSerializable(typeof(MyEnum))]
public partial class MyJsonSerializerContext : JsonSerializerContext { }

I have many enums. Is it possible to create a global policy so that each enum is converted into its string representation and we avoid attributes?


Solution

  • As stated in How to use source generation in System.Text.Json: Blanket policy, you can apply [JsonSourceGenerationOptions(UseStringEnumConverter = true)] to your serialization contexts to force all enums to be serialized as strings:

    Instead of using the JsonStringEnumConverter<TEnum> type, you can apply a blanket policy to serialize enums as strings by using the JsonSourceGenerationOptionsAttribute. Create a JsonSerializerContext class and annotate it with the JsonSerializableAttribute and JsonSourceGenerationOptionsAttribute attributes

    Thus you should modify your MyJsonSerializerContext as follows:

    [JsonSourceGenerationOptions(UseStringEnumConverter = true)]
    [JsonSerializable(typeof(MyEnum))]
    public partial class MyJsonSerializerContext : JsonSerializerContext { }
    

    The code shown in the question does not use a naming policy such as JsonNamingPolicy.CamelCase for enum serialization. If you need one, note that, as indicated in issue #92828, as of .NET 8 there does not seem to be a way to configure one with this approach. I.e. the setting UseStringEnumConverter = true lacks feature parity with new JsonStringEnumConverter(JsonNamingPolicy.CamelCase). The workaround suggested by MSFT's Eirik Tsarpalis is to apply the required converters to the serialization context instead of to each enum:

    public class CamelCaseEnumConverter<TEnum>() : 
        JsonStringEnumConverter<TEnum>(JsonNamingPolicy.CamelCase) where TEnum : struct, Enum;
    
    [JsonSourceGenerationOptions(
        Converters = new[] { 
            // Add all known enums here
            typeof(CamelCaseEnumConverter<MyEnum>)}),
    // Add all known enums here also (which you were already doing):
     JsonSerializable(typeof(MyEnum))]
    public partial class MyJsonSerializerContext : JsonSerializerContext { }
    

    For more see: Use a Blanket policy to serialize enums as strings with snake case.