Десериализация Enum из DescriptionAttribute с использованием пользовательского JSON.NET JsonConverter перестала работать

Нужна помощь с Newtonsoft Json на ядре asp.net 2.2. У меня есть JsonEnumConverter<T>, который отвечал за сериализацию/десериализацию значений из DescriptionAttribute из типа Enum. Примерно 2 недели назад все работало нормально, а сейчас вообще перестало работать.

вот что у меня есть:

//From PerformersController: 
public async Task<ActionResult<PagedPerformers>> GetPagedPerformersAsync([FromQuery] PerformerRequest performerRequest) { ... }

    [JsonObject]
    public class PerformerRequest : PageRequest
    {
        [FromQuery(Name = "performer_id")]
        [JsonProperty(PropertyName = "performer_id", Order = 1)]
        public override string Id { get; set; }
        ....
    }

    [JsonConverter(typeof(JsonEnumConverter<SortDirectionType>))]
    public enum SortDirectionType
    {
        [Description("asc")]
        ASCENDING,
        [Description("desc")]
        DESCENDING
    }

    public abstract class PageRequest
    {
        [FromQuery(Name = "page")]
        [JsonProperty("page")]
        public int Page { get; set; }

        [FromQuery(Name = "limit")]
        [JsonProperty("limit")]
        public int PageSize { get; set; } = 100;

        [FromQuery(Name = "sort_field")]
        [JsonProperty("sort_field")]
        public string SortField { get; set; } //= "Id";

        [FromQuery(Name = "sort_dir")] [JsonConverter(typeof(JsonEnumConverter<SortDirectionType>))]
        [JsonProperty("sort_dir")]
        public SortDirectionType SortDirection { get; set; }

        [FromQuery(Name = "id")]
        [JsonProperty("id")]
        public virtual string Id { get; set; }
    }

    public class JsonEnumConverter<T> : JsonConverter where T : struct, IComparable, IConvertible, IFormattable
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(T);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var type = typeof(T);

            if (!type.IsEnum) throw new InvalidOperationException();

            var enumDescription = (string)reader.Value;

            return enumDescription.GetEnumValueFromDescription<T>();
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var type = typeof(T);

            if (!type.IsEnum) throw new InvalidOperationException();

            if (value != null)
            {
                if (value is Enum sourceEnum)
                {
                    writer.WriteValue(sourceEnum.GetDescriptionFromEnumValue());
                }
            }
        }
    }

    public static class EnumExtensions
    {
        public static string GetDescriptionFromEnumValue(this Enum @enum)
        {
            FieldInfo fi = @enum.GetType().GetField(@enum.ToString());

            DescriptionAttribute[] attributes =
                (DescriptionAttribute[])fi.GetCustomAttributes(
                typeof(DescriptionAttribute),
                false);

            if (attributes != null &&
                attributes.Length > 0)
                return attributes[0].Description;
            else
                return @enum.ToString();
        }

        public static T GetEnumValueFromDescription<T>(this string description)
        {
            var type = typeof(T);

            if (!type.IsEnum)
                throw new InvalidOperationException();

            foreach (var field in type.GetFields())
            {
                if (Attribute.GetCustomAttribute(field,
                    typeof(DescriptionAttribute)) is DescriptionAttribute attribute)
                {
                    if (attribute.Description == description)
                        return (T)field.GetValue(null);
                }
                else
                {
                    if (field.Name == description)
                        return (T)field.GetValue(null);
                }
            }

            throw new ArgumentException($"No matching value for enum {nameof(T)} found from {description}.",$"{nameof(description)}"); // or return default(T);
        }
}

это работало абсолютно нормально до недавнего времени. Теперь я не уверен, что происходит, я сразу получаю ответ ValidationProblemDetails. Если я отключу недопустимый фильтр состояния модели asp.net core 2.2, тогда modelState.IsValid все равно будет иметь значение false. Если я поставлю точку останова в ReadJson моего JsonEnumConverter, она даже не сработает. Даже безуспешно пытался установить JsonSerializerSettings при запуске. Уже пробовали заменить Description на EnumMember и StringEnumConverter. Все та же проблема. Похоже, что есть проблема с ModelBinder и Json.NET, которые плохо взаимодействуют друг с другом.

ПРИМЕЧАНИЕ. Эта проблема возникает в ASP.NET Core 2.2. Предлагать решения для версии 3.0 бесполезно!!


person BRBdot    schedule 19.12.2019    source источник
comment
Вы перешли на asp.net-core-3.0? Если это так, Json.NET больше не является сериализатором по умолчанию, вместо этого Microsoft представила свой собственный сериализатор для домашнего использования system.text.json< /а>. См.: Куда делись IMvcBuilder AddJsonOptions в .Net Core 3.0?, где объясняется, как вернуться к Json.NET.   -  person dbc    schedule 19.12.2019
comment
Я не. все еще использую <TargetFramework>netcoreapp2.2</TargetFramework>.   -  person BRBdot    schedule 19.12.2019
comment
Если вы используете aspnet core 3, вы можете попробовать эту библиотеку: github.com/StefH/ System.Text.Json.EnumExtensions   -  person Stef Heyenrath    schedule 06.01.2020
comment
@StefHeyenrath с использованием ядра asp.net 2.2 ... Хотя это отличное решение, оно на самом деле не помогает мне. Спасибо за вашу помощь!   -  person BRBdot    schedule 06.01.2020
comment
@BRBdot вы когда-нибудь находили решение для .net core 2.2? Я столкнулся с той же проблемой...   -  person Ben Power    schedule 02.10.2020
comment
Если вы используете .net core 2.2+, вам обязательно следует проверить ответ @StefHeyenrath выше по ссылке на github. Мне помогло на 100%!!   -  person BRBdot    schedule 02.10.2020
comment
@StefHeyenrath, если вы хотите обновить свой комментарий до ответа, я отмечу его как решенный.   -  person BRBdot    schedule 02.10.2020
comment
@BRBdot: я добавил ответ.   -  person Stef Heyenrath    schedule 05.10.2020


Ответы (1)


Если вы используете aspnet core 3/netstandard 2.1, вы можете попробовать эту библиотеку https://github.com/StefH/System.Text.Json.EnumExtensions, который определяет некоторые расширения JsonStringEnumConverter для поддержки таких атрибутов, как EnumMember, Display и Description.

person Stef Heyenrath    schedule 03.10.2020