Переключатель поведения привязки модели ядра ASP.NET - PullRequest
3 голосов
/ 24 апреля 2019

Во время некоторых серьезных рефакторингов API кажется, что я изменил что-то, влияющее на поведение привязки модели / валидации модели.

Я пытался исследовать изменения, я не могу понять, что вызвало изменение.

У меня MyApiController наследуется от ControllerBase. MyApiController имеет метод post, получающий модель запроса (созданный с помощью шаблона API по умолчанию без HTTPS, предоставляющего типичный ValuesController).

  using Microsoft.AspNetCore.Mvc;
  using Microsoft.Extensions.Logging;
  using Newtonsoft.Json;
  using System;
  using System.Threading.Tasks;

  namespace XperimentModelBinding.Controllers
  {

    [ApiController]
    [Route("api/[controller]")]
    public class MyApiController : ControllerBase
    {

      public ILogger<MyApiController> Logger { get; }

      public MyApiController(ILogger<MyApiController> logger)
      {
        Logger = logger ?? throw new ArgumentNullException(nameof(logger));
      }


      [HttpPost()]
      public async Task<IActionResult> PostModel([FromBody] MyCreateRequestModel request)
      {

        Logger.LogInformation("PostModel: " + JsonConvert.SerializeObject(request, Formatting.None));

        if (!ModelState.IsValid) return BadRequest(ModelState);

        return Ok();

      }
    }
  }

Модель, которую я использую:

  using System.ComponentModel.DataAnnotations;

  namespace XperimentModelBinding
  {

    public class MyCreateRequestModel
    {

      [Required]
      [StringLength(10)]
      public string Name { get; set; }

      [Required]
      [Range(1, 5)]
      public int Value { get; set; }

    }

  }

Запуск и установка точки останова на регистраторе.

Тестирование с почтальоном:

Тест 1:

  {
    "Name": "1234567890",
    "Value": 1
  }

Точка останова получает удар, возвращает 200 OK (как и ожидалось).

Тест 2:

  {
    "Name": null,
    "Value": 1
  }

точка останова не получена, и возвращаемая модель:

  {
    "errors": {
        "Name": [
            "The Name field is required."
        ]
    },
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "80000006-0000-ff00-b63f-84710c7967bb"
  }

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

{
    "Name": [
        "The Name field is required."
    ]
}

Что изменилось: по запросу с неверной моделью был вызван мой метод, и я проверил с помощью ModelState.IsValid, были ли ошибки. Это было здорово, потому что я создал свою модель пользовательского ответа таким образом.

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

Что изменилось, что мой метод больше не вызывается?

Ответы [ 2 ]

4 голосов
/ 24 апреля 2019

Он подключен к атрибуту [ApiController] из ссылка

Контроллеры Web API не должны проверять ModelState.IsValid, если они имеют атрибут> [ApiController].В этом случае автоматический ответ HTTP 400, содержащий сведения о проблеме, возвращается, когда состояние модели недопустимо.Для получения дополнительной информации см. Автоматические ответы HTTP 400.

1 голос
/ 24 апреля 2019

Возможно, вы захотите использовать ConfigureApiBehaviorOptions внутри services.AddMvc() в Startup.cs, чтобы настроить пользовательское сообщение об ошибке на неверный запрос модели.

services.AddMvc()
    .ConfigureApiBehaviorOptions(options => {
        options.InvalidModelStateResponseFactory = actionContext =>
        {
            var modelState = actionContext.ModelState.Values;
            return new BadRequestObjectResult(new ErrorResult(modelState));
        };
    });
});

И определите свой ErrorResult класс, как вы хотите, например:

public class ErrorResult
{
    public int code { get; set; }
    public string message { get; set; }

    public ErrorResult()
    {
    }

    public ErrorResult(ModelStateDictionary.ValueEnumerable modelState)
    {
        // This will take the error message coming directly from modelState
        foreach (var value in modelState)
        {
            if (value.Errors.Count > 0)
            {
                code = 900; // Or use a code handler or whatever
                message = value.Errors.FirstOrDefault().ErrorMessage;
                break;
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...