Módulo 3 · Arquitetura MVC — Capítulo 05

Model Binding e Validação

Como texto de um formulário HTML vira um objeto C# tipado — e como validar isso antes de qualquer regra de negócio rodar.

1. Model Binding — de texto para objeto tipado

Toda requisição HTTP chega como texto (query string, corpo do formulário, corpo JSON). Model binding é o processo automático do ASP.NET Core que lê esse texto e monta um objeto C# — convertendo tipos, casando nomes de campo com propriedades, tudo antes do seu código de Action rodar:

C# model binding em ação
[HttpPost]
public async Task<IActionResult> Novo(ClienteCadastroViewModel modelo)
{
    // "modelo" já chega aqui totalmente preenchido —
    // o framework já leu o corpo do POST e converteu cada campo
    ...
}
nome=Ana&email=ana@x.com corpo do POST (texto puro) ClienteCadastroViewModel {'{'} Nome="Ana", Email="ana@x.com" {'}'} Model binding casa cada campo do formulário com uma propriedade do modelo pelo nome.

Fig. 1 — Model binding transforma texto de requisição em objeto tipado antes da Action executar.

2. Fontes de binding: [FromForm], [FromQuery], [FromBody], [FromRoute]

Por padrão, o model binding procura o valor em várias fontes automaticamente. Atributos deixam a origem explícita quando necessário:

C# controlando a origem de cada valor
[HttpGet("clientes/buscar")]
public IActionResult Buscar([FromQuery] string nome) // ?nome=ana
{
    ...
}

[HttpGet("clientes/{id:int}")]
public IActionResult Detalhes([FromRoute] int id) // /clientes/42
{
    ...
}

[HttpPost("clientes")]
public IActionResult Criar([FromBody] ClienteCadastroViewModel modelo) // JSON no corpo
{
    ...
}

3. Data Annotations — validação declarativa

Você já viu isso brevemente no capítulo anterior. Data Annotations são atributos que descrevem regras de validação direto na classe, sem precisar de ifs espalhados pelo Controller:

C# Data Annotations mais usadas
public class ClienteCadastroViewModel
{
    [Required(ErrorMessage = "O nome é obrigatório")]
    [StringLength(100, MinimumLength = 2)]
    public string Nome { get; set; } = string.Empty;

    [Required]
    [EmailAddress(ErrorMessage = "E-mail inválido")]
    public string Email { get; set; } = string.Empty;

    [Range(18, 120, ErrorMessage = "Idade deve estar entre 18 e 120")]
    public int Idade { get; set; }

    [RegularExpression(@"^\d{5}-\d{3}$", ErrorMessage = "CEP inválido")]
    public string Cep { get; set; } = string.Empty;
}

4. Checando a validação no Controller

C# ModelState.IsValid
[HttpPost]
public async Task<IActionResult> Novo(ClienteCadastroViewModel modelo)
{
    if (!ModelState.IsValid)
        return View(modelo); // devolve a mesma tela, com os erros visíveis via Tag Helpers

    await _service.CriarAsync(ClienteMapper.ParaEntidade(modelo));
    return RedirectToAction(nameof(Listar));
}

ModelState é preenchido automaticamente pelo framework durante o model binding — cada Data Annotation violada vira uma entrada nele. Do lado da View, o Tag Helper asp-validation-for (visto no capítulo 3) exibe a mensagem correspondente ao lado de cada campo.

5. Validação customizada

Quando uma regra não se encaixa num atributo pronto, implemente IValidatableObject:

C# validação que depende de múltiplos campos
public class PedidoCadastroViewModel : IValidatableObject
{
    public DateTime DataEntregaDesejada { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext contexto)
    {
        if (DataEntregaDesejada < DateTime.Today)
        {
            yield return new ValidationResult(
                "A data de entrega não pode ser no passado",
                new[] { nameof(DataEntregaDesejada) });
        }
    }
}
Validação de tela não substitui validação de dados

Data Annotations validam a forma dos dados antes de chegar à regra de negócio — mas nunca confie só nelas. As checagens de integridade que você já implementou nas procedures do Módulo 2 (como THROW quando estoque é insuficiente) continuam sendo a última linha de defesa, porque a Action pode ser chamada de outras formas além de um formulário HTML validado (uma chamada de API direta, por exemplo).

6. Onde isso te leva

Com model binding e validação cobertos, os dois últimos capítulos deste módulo tratam de como o ASP.NET Core monta as dependências que os Controllers recebem (Injeção de Dependência) e o que acontece com uma requisição antes/depois de chegar numa Action (Filters e Middlewares).

📌 Resumo do capítulo

  • Model binding converte texto de requisição (form, query string, JSON, rota) em objetos C# tipados automaticamente.
  • [FromForm], [FromQuery], [FromBody], [FromRoute] tornam a origem explícita quando necessário.
  • Data Annotations ([Required], [EmailAddress], [Range]...) validam declarativamente; ModelState.IsValid checa o resultado.
  • IValidatableObject cobre regras que dependem de múltiplos campos.
  • Validação de tela nunca substitui as checagens de integridade já feitas nas procedures.

✏️ Praticando

  1. Adicione Data Annotations completas em ClienteCadastroViewModel, incluindo [Compare] para confirmação de senha.
  2. Implemente a Action Novo (POST) checando ModelState.IsValid e devolvendo a View com erros quando inválido.
  3. Implemente IValidatableObject numa classe que valide se uma data de início é anterior a uma data de término.