1

On dotnet 6, System.Text.Json JsonSerializer is unable to parse an enum that starts with characters like "<". There's a reproduction here:

https://dotnetfiddle.net/O3MdPn

overly simplified,

using System;
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;

public class Program {
    public enum Operator {
        [EnumMember(Value = "<=")] LessOrEqual,
        [EnumMember(Value = "lesseq")] LessEq,
    }

    public class BasicJson { 
            public Operator Operator {get; init;}
    }

    public static void Main() {
        JsonSerializerOptions SerializationOptions = new() {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        IgnoreNullValues = true,
        Converters = {
                new JsonStringEnumConverter()
            },

    };
        var serialized = JsonSerializer.Deserialize<BasicJson>("{\"operator\": \"<=\"}", SerializationOptions);
        Console.Write($"{serialized.Operator}");

    }

}

results in the following error

Unhandled exception. System.Text.Json.JsonException: The JSON value could not be converted to Program+Operator. Path: $.operator | LineNumber: 0 | BytePositionInLine: 17.
   at System.Text.Json.ThrowHelper.ThrowJsonException(String message)
   at System.Text.Json.Serialization.Converters.EnumConverter`1.ReadAsPropertyNameCore(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Converters.EnumConverter`1.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable`1 actualByteCount)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
   at Program.Main()

Changing "<=" to "lesseq" works as expected. Is there some Serialization setting I need to change in order to support special characters like "<" ?

Edit:

It seems that System.Text.Json does not respect the EnumMember attribute whatsoever, it doesn't actually have anything to do with special characters, it's just that the Serializer can only parse exact matches of the enum name (or camel case matches if you specify that as the naming policy).

A workaround is to use Macross.Extensions.Json package: https://www.nuget.org/packages/Macross.Json.Extensions/

and then add

    Converters = {
                new  Macross.Json.Extensions.JsonStringEnumMemberConverter(),
                new JsonStringEnumConverter()
            },

To the converters. This properly parses enums based on their EnumMember Value attribute.

dbc
  • 104,963
  • 20
  • 228
  • 340
Aaron Wilson
  • 130
  • 7

1 Answers1

2

Added to the original post, but here is the resolution:

It seems that System.Text.Json does not respect the EnumMember attribute whatsoever, it doesn't actually have anything to do with special characters, it's just that the Serializer can only parse exact matches of the enum name (or camel case matches if you specify that as the naming policy).

A workaround is to use Macross.Extensions.Json package: https://www.nuget.org/packages/Macross.Json.Extensions/

and then add

Converters = {
            new  Macross.Json.Extensions.JsonStringEnumMemberConverter(),
            new JsonStringEnumConverter()
        },

To the converters. This properly parses enums based on their EnumMember Value attribute.

Aaron Wilson
  • 130
  • 7