Runtime: Make JsonStringEnumConverter support nullable enums

Created on 25 Sep 2019  路  10Comments  路  Source: dotnet/runtime

Right now, the JsonStringEnumConverter converter does not support nullable enums.

I think it should.

area-System.Text.Json enhancement

Most helpful comment

While this isn't the most elegant solution, it does serve as a workaround until this gets sorted.

public class StringNullableEnumConverter<T> : JsonConverter<T>
{
    private readonly Type _underlyingType;

    public StringNullableEnumConverter()
    {
        _underlyingType = Nullable.GetUnderlyingType(typeof(T));
    }

    public override bool CanConvert(Type typeToConvert)
    {
        return typeof(T).IsAssignableFrom(typeToConvert);
        //return true;
    }

    public override T Read(ref Utf8JsonReader reader,
        Type typeToConvert, 
        JsonSerializerOptions options)
    {
        string value = reader.GetString();
        if (String.IsNullOrEmpty(value)) return default;

        try
        {
            return (T)Enum.Parse(_underlyingType, value);
        }
        catch (ArgumentException ex)
        {
            throw new JsonException("Invalid value.", ex);
        }
    }

    public override void Write(Utf8JsonWriter writer, 
        T value, 
        JsonSerializerOptions options)
    {
        writer.WriteStringValue(value?.ToString());
    }
}

and you can attach it to your property by decorating it with this

[JsonConverter(typeof(StringNullableEnumConverter<Nullable<MyEnum>>))]
public MyEnum? MyNullableEnum { get; set; }

All 10 comments

cc @JeremyKuhne

5.0?

Is there any chance we can make it earlier, if I contribute with a PR? :angel:

Is there any chance we can make it earlier, if I contribute with a PR?

It would be great if you'd like to submit a fix for this against master and we can evaluate whether it makes sense to port it to 3.1 based on risk/complexity and consumer need. Let me know if you need any help with that and definitely ping me on your PR for review whenever you get the chance to work on the fix :)

Can you explain your scenario/use case which is being blocked by the lack of this feature? I also want to try and see if there is a feasible workaround for nullable enums (either via a custom converters or creating your own JsonStringEnumConverter wrapper).

Thanks for the offer - in that case, perhaps you can help with dotnet/corefx#41344?

We are also blocked from using System.Text.JSON in our API. We have issues with Swagger since JsonStringEnumConverter doesn't support nullable enums.

I have the same problem, had to use Newtonsoft because of that.

While this isn't the most elegant solution, it does serve as a workaround until this gets sorted.

public class StringNullableEnumConverter<T> : JsonConverter<T>
{
    private readonly Type _underlyingType;

    public StringNullableEnumConverter()
    {
        _underlyingType = Nullable.GetUnderlyingType(typeof(T));
    }

    public override bool CanConvert(Type typeToConvert)
    {
        return typeof(T).IsAssignableFrom(typeToConvert);
        //return true;
    }

    public override T Read(ref Utf8JsonReader reader,
        Type typeToConvert, 
        JsonSerializerOptions options)
    {
        string value = reader.GetString();
        if (String.IsNullOrEmpty(value)) return default;

        try
        {
            return (T)Enum.Parse(_underlyingType, value);
        }
        catch (ArgumentException ex)
        {
            throw new JsonException("Invalid value.", ex);
        }
    }

    public override void Write(Utf8JsonWriter writer, 
        T value, 
        JsonSerializerOptions options)
    {
        writer.WriteStringValue(value?.ToString());
    }
}

and you can attach it to your property by decorating it with this

[JsonConverter(typeof(StringNullableEnumConverter<Nullable<MyEnum>>))]
public MyEnum? MyNullableEnum { get; set; }

To slightly improve the performance of the method above, we can remove the try/catch block with

// for performance, parse with ignoreCase:false first.
if (!Enum.TryParse(_underlyingType, value, ignoreCase: false, out object result) &&
    !Enum.TryParse(_underlyingType, value, ignoreCase: true, out result))
{
    throw new JsonException($"Unable to convert \"{value}\" to Enum \"{_underlyingType}\".");
}
return (T)result;

the try and catch is a bit expensive for something that can be solved with TryParse

For anyone blocked by this, here's a NuGet package with a converter (JsonStringEnumMemberConverter) we can use ahead of the 5.0 drop: Macross.Json.Extensions

Supports nullable enum types and adds EnumMemberAttribute support.

This is fixed for 5.0 following https://github.com/dotnet/runtime/pull/32006.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

matty-hall picture matty-hall  路  3Comments

nalywa picture nalywa  路  3Comments

jchannon picture jchannon  路  3Comments

yahorsi picture yahorsi  路  3Comments

noahfalk picture noahfalk  路  3Comments