O JsonStringEnumConverter (System.Text.Json) suporta valores nulos?

8

Estou mudando meu código do .NET Core 2.x para o .NET Core 3.x (ou seja, use a biblioteca nativa System.Text.Json). Ao fazer isso, deparei-me com alguns problemas de como o Newtonsoft.Jsonsuporte anterior para enumerações anuláveis ​​não tem um caminho de migração claro no momento - parece que não há suporte no .NET Core 3.x ?.

Por exemplo, usando Newtonsoft.Json, o conversor JSON suportava enumerações anuláveis, da seguinte forma:

public enum UserStatus
{
    NotConfirmed,
    Active,
    Deleted
}

public class User
{
    public string UserName { get; set; }

    [JsonConverter(typeof(StringEnumConverter))]  // using Newtonsoft.Json
    public UserStatus? Status { get; set; }       // Nullable Enum
}

A versão atual da biblioteca nativa System.Text.Jsonparece não suportar isso.

Como eu resolvo este problema? Não consigo migrar meu código!

Svek
fonte
1
O suporte nativo ao suporte de enum anulável no JsonStringEnumConverter está sendo rastreado em github.com/dotnet/corefx/issues/41307 .
Nitin Agarwal
@NitinAgarwal Vamos torcer para que seja implementado em breve!
Svek 31/01

Respostas:

6

Infelizmente, atualmente não há suporte " System.Text.Jsonpronto para uso " para converter enumerações anuláveis.

No entanto, existe uma solução usando seu próprio conversor personalizado . (veja abaixo) .


A solução. Use um conversor personalizado.

Você pode anexá-lo à sua propriedade decorando-o com o conversor personalizado:

// using System.Text.Json
[JsonConverter(typeof(StringNullableEnumConverter<UserStatus?>))]  // Note the '?'
public UserStatus? Status { get; set; }                            // Nullable Enum

Aqui está o conversor:

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

    public StringNullableEnumConverter() : this(null) { }

    public StringNullableEnumConverter(JsonSerializerOptions options)
    {
        // for performance, use the existing converter if available
        if (options != null)
        {
            _converter = (JsonConverter<T>)options.GetConverter(typeof(T));
        }

        // cache the underlying type
        _underlyingType = Nullable.GetUnderlyingType(typeof(T));
    }

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

    public override T Read(ref Utf8JsonReader reader, 
        Type typeToConvert, JsonSerializerOptions options)
    {
        if (_converter != null)
        {
            return _converter.Read(ref reader, _underlyingType, options);
        }

        string value = reader.GetString();

        if (String.IsNullOrEmpty(value)) return default;

        // 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;
    }

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

Espero que ajude até que haja suporte nativo sem a necessidade de um conversor personalizado!

Svek
fonte
1

Você deve conseguir recuperar seu comportamento original instalando o nuget Newtonsoft JSON e colocando isso no seu código, suponho que você esteja migrando um aplicativo ASP:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson();
}
Michal Hosala
fonte
1
A idéia é usar o mais recente "melhor" (desempenho e compatibilidade da Microsoft a longo prazo) System.Text.Jsonfornecido com o ASP.NET Core 3.x. --- A "migração" mencionada era de 2.x para 3.x
Svek
@Svek Eu posso me relacionar com isso, no entanto, todas as novas funcionalidades brilhantes do Json Core têm algumas lacunas, então, por enquanto, a equipe decidiu usar essa abordagem, que espero que possa ser útil para outras pessoas também, pois responde à sua pergunta em sua forma original - "como resolver este problema?".
Michal Hosala 01/01