Какой ответ следует возвращать клиенту при неуспешной валидации запроса в ASP.NET Core?

«Какой ответ следует возвращать клиенту при неуспешной валидации запроса в ASP.NET Core?» — вопрос из категории ASP.NET Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Стандартной и рекомендуемой практикой является возврат HTTP-статуса 400 Bad Request с детализированным объектом, описывающим ошибки валидации. В ASP.NET Core для этого есть встроенные механизмы.

Самый простой способ — использовать ControllerBase.ValidationProblem():

[HttpPost]
public IActionResult CreateProduct([FromBody] ProductCreateDto dto)
{
    if (!ModelState.IsValid)
    {
        // Автоматически возвращает 400 с объектом ProblemDetails
        return ValidationProblem(ModelState);
    }
    // Логика обработки валидного запроса...
}

Для большего контроля можно явно возвращать BadRequest(Object):

if (!ModelState.IsValid)
{
    return BadRequest(new
    {
        Status = 400,
        Title = "Validation Failed",
        Errors = ModelState.Values
            .SelectMany(v => v.Errors.Select(e => e.ErrorMessage))
    });
}

Стандартизированный ответ (используя ProblemDetails): Контроллер автоматически форматирует ответ в стандартном формате RFC 7807 (Problem Details):

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "Email": ["The Email field is required.", "The Email field is not a valid e-mail address."],
    "Age": ["The field Age must be between 18 and 100."]
  }
}

Ключевые принципы:

  1. Статус 400: Четко указывает клиенту на ошибку в запросе.
  2. Детализация ошибок: Указывает конкретные поля и сообщения, что позволяет клиенту исправить запрос.
  3. Консистентность: Использование стандартного формата (ProblemDetails) помогает клиентам единообразно обрабатывать ошибки.
  4. Безопасность: Никогда не возвращайте стек-трейсы или внутренние детали исключений.