Unterstützt JsonStringEnumConverter (System.Text.Json) Nullwerte?

8

Ich verschiebe meinen Code von .NET Core 2.x auf .NET Core 3.x (dh verwende die native Bibliothek System.Text.Json). Dabei bin ich auf einige Probleme Newtonsoft.Jsongestoßen, bei denen die frühere Unterstützung für nullfähige Aufzählungen derzeit keinen eindeutigen Migrationspfad hat - es sieht so aus, als würde sie in .NET Core 3.x nicht unterstützt.

Bei Verwendung Newtonsoft.Jsondes JSON-Konverters wurden beispielsweise nullfähige Aufzählungen unterstützt, z.

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
}

Die aktuelle Version der nativen Bibliothek System.Text.Jsonscheint dies nicht zu unterstützen.

Wie löse ich dieses Problem? Ich kann meinen Code nicht migrieren!

Svek
quelle
1
Die native Unterstützung für die Unterstützung von nullbaren Enums in JsonStringEnumConverter wird unter github.com/dotnet/corefx/issues/41307 verfolgt .
Nitin Agarwal
@NitinAgarwal Hoffen wir, dass es bald implementiert wird!
Svek

Antworten:

6

Leider gibt es derzeit keine "out-of-the-box" System.Text.Json-Unterstützung für die Konvertierung von nullbaren Aufzählungen.

Es gibt jedoch eine Lösung, indem Sie Ihren eigenen benutzerdefinierten Konverter verwenden . (siehe unten) .


Die Lösung. Verwenden Sie einen benutzerdefinierten Konverter.

Sie können es an Ihrem Grundstück anbringen, indem Sie es mit dem benutzerdefinierten Konverter dekorieren:

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

Hier ist der Konverter:

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());
    }
}

Hoffe, das hilft, bis es native Unterstützung gibt, ohne dass ein benutzerdefinierter Konverter erforderlich ist!

Svek
quelle
1

Sie sollten in der Lage sein, Ihr ursprüngliches Verhalten wiederherzustellen, indem Sie das Newtonsoft JSON-Nuget installieren und dieses in Ihren Code einfügen. Ich nehme an, Sie migrieren eine ASP-App:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson();
}
Michal Hosala
quelle
1
Die Idee ist, das neuere, "bessere" (Leistung und Microsoft-Kompatibilität auf lange Sicht) zu verwenden System.Text.Json, das mit ASP.NET Core 3.x geliefert wurde. --- Die erwähnte "Migration" war von 2.x bis 3.x
Svek
@Svek Ich kann mich darauf beziehen, aber alle neuen, glänzenden Json Core-Funktionen weisen einige Lücken auf. Daher hat sich das Team vorerst entschieden, diesen Ansatz lieber zu verwenden, was hoffentlich auch für einige andere Personen hilfreich sein kann, da er Ihre Frage beantwortet seine ursprüngliche Form - "wie man dieses Problem löst?".
Michal Hosala