ModelState e atributos built-in
ResumoA validação de modelo do ASP.NET Core usa Data Annotations e o
ModelState. Com[ApiController], respostas400para modelos inválidos são automáticas. Vemos atributos built-in e como criar atributos e objetos validáveis customizados.
1. Objetivos de Aprendizagem#
- Usar Data Annotations (
[Required],[Range],[StringLength]). - Entender
ModelStatee a validação automática do[ApiController]. - Criar um
ValidationAttributecustomizado e usarIValidatableObject.
2. Pré-requisitos#
- DTOs de criação/atualização (Módulos 09/11).
3. Conceito#
O ModelState acumula erros de binding e validação. Com [ApiController], se ModelState for inválido, o framework retorna 400 Bad Request com ValidationProblemDetails antes de a ação executar. O porquê: menos código repetido e respostas de erro consistentes.
4. Mão na Massa#
4.1. Setup#
Data Annotations já estão disponíveis (System.ComponentModel.DataAnnotations).
4.2. Implementação Passo a Passo#
- Atributos built-in no DTO:
using System.ComponentModel.DataAnnotations;
public record ProdutoForCreationDto(
[property: Required(ErrorMessage = "O nome é obrigatório.")]
[property: StringLength(60, MinimumLength = 2)]
string Nome,
[property: Range(0.01, 1_000_000, ErrorMessage = "Preço deve ser positivo.")]
decimal Preco);
- Atributo customizado:
public class NomeSemNumerosAttribute : ValidationAttribute
{
protected override ValidationResult? IsValid(object? value, ValidationContext ctx)
{
if (value is string s && s.Any(char.IsDigit))
return new ValidationResult("O nome não pode conter números.");
return ValidationResult.Success;
}
}
IValidatableObjectpara validação com múltiplos campos:
public class ProdutoForUpdateDto : IValidatableObject
{
public string Nome { get; set; } = default!;
public decimal Preco { get; set; }
public decimal? PrecoPromocional { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext ctx)
{
if (PrecoPromocional is > 0 && PrecoPromocional >= Preco)
yield return new ValidationResult(
"Preço promocional deve ser menor que o preço.",
new[] { nameof(PrecoPromocional) });
}
}
4.3. Executando#
curl -i -X POST .../produtos -H "Content-Type: application/json" -d '{"nome":"","preco":-1}'
# HTTP/1.1 400 Bad Request (ValidationProblemDetails com os erros)
5. Exemplo Completo#
Com [ApiController], nenhum if (!ModelState.IsValid) return BadRequest(...) é necessário para atributos — o framework cuida. Para validações após patch, use TryValidateModel (Módulo 26).
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
| Validar na borda (DTO de entrada) | Deixar dados inválidos chegarem ao domínio/banco |
| Mensagens de erro claras e específicas | Mensagens genéricas que não ajudam o cliente |
Usar IValidatableObject para regras multi-campo | Espalhar essa lógica pelo controller |
AtençãoData Annotations validam formato/estrutura, não regras de negócio complexas. Regras de negócio pertencem à Service Layer (ou FluentValidation, Módulo 44).
7. Segurança e Produção#
- Validar limites de tamanho (
StringLength,MaxLength) mitiga payloads abusivos. - Nunca confie apenas na validação do cliente; a validação no servidor é a que protege.
8. Exercícios#
- Fácil: aplique
[Required]e[Range]aoProdutoForCreationDto. - Médio: crie um atributo que exija que o nome comece com maiúscula.
- Desafio: implemente
IValidatableObjectque valide coerência entre três campos.
9. Resumo#
A validação usa Data Annotations e ModelState; [ApiController] gera 400 automático. Atributos customizados e IValidatableObject cobrem regras específicas na borda da aplicação.
10. Próximos Passos#
A seguir, particularidades da validação em POST, PUT e PATCH.
11. Referências#
- Microsoft Learn — Validação de modelo no ASP.NET Core
- Microsoft Learn — Atributo ApiController e respostas automáticas 400
- Microsoft Learn — Data Annotations