Пользовательский ModelBinder, производный от DefaultModelBinder, не применяет атрибут JsonProperty - PullRequest
0 голосов
/ 18 июня 2020

В нашем текущем проекте (ASP. NET MVC /. NET Framework 4.6.1) нам нужны наши MVC контроллеры, чтобы иметь возможность обрабатывать JSON запросов и возвращать JSON ответов, поэтому мы выбрали пакет Newtosnsof. Json (v.11.0.2) для обработки всех JSON сериализации / десериализации.

В этом направлении мы разработали настраиваемый ModelBinder для обработки десериализации входящих моделей и настраиваемый JsonNetResult для обеспечения сериализации исходящих ответов.

Более того, для свойств наших моделей мы используйте атрибут JsonProperty, чтобы указать регистр верблюда и, в некоторых случаях, другие имена. Мы также используем DataAnnotations для проверки значений свойств моделей. Например:

public class TestModel
{
    [JsonProperty(PropertyName = "id")]
    [Required(AllowEmptyStrings = false)]
    public string Id { get; set; }

    [JsonProperty(PropertyName = "text")]
    [Required(AllowEmptyStrings = false)]
    public string Name { get; set; }
}

Пользовательский ModelBinder является производным от DefaultModelBinder и переопределяет метод CreateModel, как показано ниже:

internal class JsonNetModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var stream = controllerContext.RequestContext.HttpContext.Request.InputStream;
        stream.Position = 0;
        var jsonString = string.Empty;
        using (var reader = new StreamReader(stream, Encoding.UTF8))
        {
            jsonString = reader.ReadToEnd();
        }
        if (!string.IsNullOrWhiteSpace(jsonString))
        {
            return JsonConvert.DeserializeObject(jsonString, modelType);
        }
        return null;
    }
}

Наш настраиваемый ModelBinder применяется в контроллере на уровне метода действия как показано ниже:

 [HttpPost]
    public ActionResult GetTest(
    [System.Web.Http.FromBody][ModelBinder(typeof(JsonNetModelBinder)] TestModel model)
    {
        ......
    }

Проблема, с которой мы сталкиваемся, заключается в том, что если имя свойства модели, применяемое атрибутом JsonProperty, не совпадает с фактическим именем свойства, независимо от корпуса имени свойства, тогда значение свойства не предоставляется ModelBinder. Похоже, что ModelBinder полностью игнорирует атрибут JsonProperty. Итак, после публикации JSON данных, которые привели бы к созданию вышеупомянутой модели, свойство «Имя» всегда равно нулю.

После исследования проблемы мы обнаружили, что наша реализация метода CreateModel возвращает модель, правильно десериализованную со всеми предоставленными значениями свойств. Итак, проблема должна возникать в каком-то другом месте в ModelBinder.

Мы также попробовали:

  1. Переопределить метод BindModel вместо метода CreateModel из DefaultModelBinder, используя код, аналогичный приведенному выше.
  2. Вместо использования DefaultModelBinder в качестве базового класса мы создали класс, который наследует интерфейс IModelBinder и реализует метод BindModel.

В обоих приведенных выше случаях случаях мы получаем правильную десериализацию всех свойств модели, но проверка DataAnnotaions не работает.

Нам нужно сохранить нашу реализацию DefaultModelBinder, чтобы иметь проверку модели на основе DataAnnotations, но для решения проблемы с помощью атрибут JsonProperty.

Заранее спасибо,
Джордж

PS Возврат к DataContractSerializer или переключение на ApiControllers не вариант.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...