Ответ
ASP.NET Core предоставляет несколько встроенных и сторонних способов для валидации моделей.
1. Атрибуты валидации (DataAnnotations)
Стандартный подход для простых правил. Активируется автоматически при использовании [ApiController].
public class CreateUserRequest
{
[Required(ErrorMessage = "Name is required.")]
[StringLength(100, MinimumLength = 2)]
public string Name { get; set; }
[EmailAddress]
public string Email { get; set; }
[Range(18, 120)]
public int Age { get; set; }
}
2. FluentValidation (Рекомендуется для сложной логики)
Библиотека для декларативного описания правил. Требует регистрации в Program.cs.
public class CreateUserRequestValidator : AbstractValidator<CreateUserRequest>
{
public CreateUserRequestValidator()
{
RuleFor(x => x.Name).NotEmpty().Length(2, 100);
RuleFor(x => x.Email).EmailAddress();
RuleFor(x => x.Age).InclusiveBetween(18, 120);
// Сложное правило
RuleFor(x => x.Email)
.Must(email => email.EndsWith("@company.com"))
.WithMessage("Only company emails are allowed.");
}
}
// Регистрация: builder.Services.AddScoped<IValidator<CreateUserRequest>, CreateUserRequestValidator>();
3. Валидация в Action-методе
С атрибутом [ApiController] невалидная модель автоматически приводит к ответу 400 BadRequest с деталями в ModelState. Вручную можно проверить так:
[HttpPost]
public IActionResult CreateUser(CreateUserRequest request)
{
if (!ModelState.IsValid) // Автоматически проверяется
{
return ValidationProblem(ModelState); // Возвращает стандартизированную ошибку
}
// Логика обработки...
}
4. Пользовательские атрибуты валидации
public class FutureDateAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
if (value is DateTime date && date > DateTime.Now)
return ValidationResult.Success;
return new ValidationResult("Date must be in the future.");
}
}
Best Practices:
- Всегда валидируйте входные данные на уровне контроллера.
- Для бизнес-правил используйте валидацию внутри доменного слоя.
- Используйте
ProblemDetailsдля стандартизации ответов об ошибках.
Ответ 18+ 🔞
Ну, смотри, в ASP.NET Core с валидацией моделей вообще веселуха, можно по-разному подъехать. Как будто в гараж заходишь — и молоток есть, и шуруповёрт, и болгарка на крайняк. Главное — не пытаться гвозди микроскопом забивать, а то нихуя не выйдет.
1. Атрибуты валидации (DataAnnotations)
Это как базовый набор, из коробки. Если у тебя [ApiController] на контроллере, то эта штука сама включается, как только ты модель в метод суёшь. Просто, но для сложных условий — туповато.
public class CreateUserRequest
{
[Required(ErrorMessage = "Name is required.")] // Без имени — нихуя не пользователь
[StringLength(100, MinimumLength = 2)] // Не меньше двух букв и не больше ста, а то заебёшься
public string Name { get; set; }
[EmailAddress] // Проверит, что там собачка есть и точка после неё
public string Email { get; set; }
[Range(18, 120)] // От 18 (чтоб не палиться) и до 120 (пока не сдох)
public int Age { get; set; }
}
2. FluentValidation (Для всего, что посерьёзнее) Вот это, блядь, мощная тема. Когда правила валидации сложнее, чем «проверить, что поле не пустое». Тут ты описываешь всё, как на духу, отдельным классом. Читается, как книга, только про правила.
public class CreateUserRequestValidator : AbstractValidator<CreateUserRequest>
{
public CreateUserRequestValidator()
{
RuleFor(x => x.Name).NotEmpty().Length(2, 100); // Тот же принцип, но красивее
RuleFor(x => x.Email).EmailAddress();
RuleFor(x => x.Age).InclusiveBetween(18, 120);
// А вот тут уже магия, например, только корпоративные мыла
RuleFor(x => x.Email)
.Must(email => email.EndsWith("@company.com"))
.WithMessage("Only company emails are allowed."); // Не с нашей почтой — иди нахуй
}
}
// Не забудь в Program.cs добавить: builder.Services.AddScoped<IValidator<CreateUserRequest>, CreateUserRequestValidator>();
3. Валидация прямо в методе контроллера
С [ApiController] вообще заморачиваться не надо — если модель кривая, фреймворк сам вернёт 400 BadRequest с подробностями, что не так. Но если очень хочется ручками потрогать — вот:
[HttpPost]
public IActionResult CreateUser(CreateUserRequest request)
{
// ModelState.IsValid уже проверен автоматически, но ты можешь добавить свою логику
if (!ModelState.IsValid) // На всякий случай, хотя обычно и так сработает
{
return ValidationProblem(ModelState); // Отправит красивую ошибку со всеми косяками
}
// Если добрался сюда — значит, данные более-менее адекватные, можно работать...
}
4. Свои, кастомные атрибуты Когда стандартных атрибутов не хватает, а лезть в FluentValidation неохота. Например, нужно проверить, что дата — в будущем.
public class FutureDateAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
if (value is DateTime date && date > DateTime.Now)
return ValidationResult.Success; // Всё ок, дата впереди
return new ValidationResult("Date must be in the future."); // А вот это уже прошлое, не катит
}
}
Как не накосячить:
- Всегда валидируй на входе в контроллер. Это как проверять документы на границе — пускать только легальных.
- Сложную бизнес-логику (типа «можно ли этому юзеру создавать заказ») валидируй уже внутри доменного слоя, а не в контроллере.
- Используй
ProblemDetailsдля ошибок. Чтобы все ответы об ошибках выглядели одинаково, а не как попало. Иначе фронтендеры тебя возненавидят, и будут правы.