Как переопределить сообщения об исключениях привязки модели Json.Net для целей локализации? - PullRequest
1 голос
/ 11 июля 2019

Я переопределил все сообщения привязки модели с переводами, используя ModelBindingMessageProvider.SetValueIsInvalidAccessor и другие значения ModelBindingMessageProvider, чтобы вернуть мои собственные строки ресурсов.

А потом я обнаружил печальную правду. Если мой контроллер API получает данные в виде JSON, то сообщения проверки ModelBindingMessageProvider не используются. Вместо этого включается Json.Net, и я получаю что-то вроде этого:

  "errors": {
    "countryId": [
      "Input string '111a' is not a valid number. Path 'countryId', line 3, position 23."
    ]
  },

Я посмотрел в GitHub источник Json.Net - действительно, похоже, что такие точные сообщения об ошибках определены с номерами строк и т. Д.

Итак, ModelState управляет их извлечением вместо использования собственных сообщений ModelBindingMessageProvider.

Я пытался отключить обработку ошибок Json.Net:

.AddJsonOptions(options =>
                {
                 ...
                    options.SerializerSettings.Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
                    {
                        // ignore them all
                        args.ErrorContext.Handled = true;
                    };
                })

но это не имело значения.

Есть ли способ отловить эти ошибки десериализации Json и перенаправить их в ModelBindingMessageProvider, чтобы мои локализованные сообщения работали?

1 Ответ

1 голос
/ 12 июля 2019

Есть ли способ отловить эти ошибки десериализации Json и перенаправить их в ModelBindingMessageProvider, чтобы мои локализованные сообщения работали?

Нет, привязка модели и ввод json разные, модельсвязыватель для FromForm, а JsonInputFormatter для FromBody.Они следуют по-другому.Вы не можете настроить сообщение об ошибке от ModelBindingMessageProvider.

Для JSON вы можете реализовать свой собственный JsonInputFormatter и изменить сообщение об ошибке, например

  1. CustomJsonInputFormatter

    public class CustomJsonInputFormatter : JsonInputFormatter
    {
        public CustomJsonInputFormatter(ILogger<CustomJsonInputFormatter> logger
            , JsonSerializerSettings serializerSettings
            , ArrayPool<char> charPool
            , ObjectPoolProvider objectPoolProvider
            , MvcOptions options
            , MvcJsonOptions jsonOptions) 
            : base(logger, serializerSettings, charPool, objectPoolProvider, options, jsonOptions)
        {
        }
        public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
        {           
            var result = await base.ReadRequestBodyAsync(context);
    
            foreach (var key in context.ModelState.Keys)
            {
                for (int i = 0; i < context.ModelState[key].Errors.Count; i++)
                {
                    var error = context.ModelState[key].Errors[i];
                    context.ModelState[key].Errors.Add($"This is translated error { error.ErrorMessage }");
                    context.ModelState[key].Errors.Remove(error);
                }
            }
            return result;
        }
    }
    
  2. Зарегистрировать CustomJsonInputFormatter

        services.AddMvc(options =>
        {                
            var serviceProvider = services.BuildServiceProvider();
            var customJsonInputFormatter = new CustomJsonInputFormatter(
                     serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger<CustomJsonInputFormatter>(),
                     serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>().Value.SerializerSettings,
                     serviceProvider.GetRequiredService<ArrayPool<char>>(),
                     serviceProvider.GetRequiredService<ObjectPoolProvider>(),
                     options,
                     serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>().Value
                );
            options.InputFormatters.Insert(0, customJsonInputFormatter);
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }
    
  3. Зарегистрировать локализованную службу в CustomJsonInputFormatter, чтобы настроить сообщение об ошибке.

...