Я перевожу свой код с .NET Core 2.x на .NET Core 3.x (то есть использую собственную библиотеку System.Text.Json). При этом я столкнулся с некоторыми проблемами, связанными с тем, что у прежней поддержки Newtonsoft.Json для обнуляемых перечислений в настоящий момент нет четкого пути миграции - похоже, что она не поддерживается в .NET Core 3.x? ,

Например, используя Newtonsoft.Json, JSON-конвертер поддерживает нумерованные перечисления, например:

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
}

Текущая версия собственной библиотеки System.Text.Json, похоже, не поддерживает это.

Как мне решить эту проблему? Я не могу перенести свой код!

16
Svek 17 Дек 2019 в 21:11

2 ответа

Лучший ответ

К сожалению, в настоящее время в System.Text.Json нет поддержки "из коробки" для преобразования перечислений, допускающих значение NULL.

Однако есть решение, использующее ваш собственный конвертер . (см. ниже) .


Решение. Используйте пользовательский конвертер.

Вы можете прикрепить его, прикрепив его к вашей собственности, украсив его с помощью специального конвертера:

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

Вот конвертер:

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

Надеюсь, что это поможет, пока не будет встроенной поддержки без необходимости пользовательского конвертера!

6
Svek 17 Дек 2019 в 18:16

Вы сможете вернуть исходное поведение, установив Newtonsoft JSON nuget и поместив это в свой код, я полагаю, вы переносите приложение ASP:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson();
}
1
Michal Hosala 31 Дек 2019 в 13:37