Pular para o conteúdo
.NETValidação e refatoração com filters
Módulo 04CRUD Completo e Validação

Validação e refatoração com filters

intermediario 30 min de leitura·Atualizado · .NET 9
Resumo

Movemos a validação repetida (checagem de nulos e ModelState) para um Action Filter reutilizável, deixando os controllers focados só no fluxo principal.

1. Objetivos de Aprendizagem#

  • Extrair validação recorrente para um Action Filter.
  • Curto-circuitar a requisição a partir do filtro quando inválida.
  • Simplificar os controllers após a refatoração.

2. Pré-requisitos#

  • Action Filters (tópico 29.1); validação (Módulo 27).

3. Conceito#

Mesmo com [ApiController] cuidando de ModelState, há validações comuns que se repetem — por exemplo, garantir que o DTO recebido não é nulo e que o ModelState é válido antes de prosseguir com regras extras. Um filtro centraliza isso e pode curto-circuitar a ação definindo context.Result.

4. Mão na Massa#

4.1. Setup#

Sem pacotes novos.

4.2. Implementação Passo a Passo#

  1. Filtro de validação:
C#
public class ValidationFilterAttribute : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Garante que o DTO (parâmetro terminado em "Dto") não é nulo
        var dto = context.ActionArguments
            .SingleOrDefault(x => x.Key.EndsWith("Dto", StringComparison.OrdinalIgnoreCase)).Value;

        if (dto is null)
        {
            context.Result = new BadRequestObjectResult("O objeto enviado é nulo.");
            return;
        }

        if (!context.ModelState.IsValid)
            context.Result = new UnprocessableEntityObjectResult(context.ModelState);
    }

    public void OnActionExecuted(ActionExecutedContext context) { }
}
  1. Registro:
C#
builder.Services.AddScoped<ValidationFilterAttribute>();
  1. Aplicação na ação:
C#
[HttpPost]
[ServiceFilter(typeof(ValidationFilterAttribute))]
public async Task<IActionResult> Criar(Guid categoriaId, [FromBody] ProdutoForCreationDto dto)
{
    var criado = await _service.Produto.CreateAsync(categoriaId, dto, false);
    return CreatedAtRoute("ProdutoById", new { categoriaId, id = criado.Id }, criado);
}

4.3. Executando#

Envie um corpo nulo ou inválido: o filtro responde 400/422 antes de a ação rodar.

5. Exemplo Completo#

Antes: cada ação repetia checagens de nulo e ModelState. Depois: os controllers ficam limpos, com a validação concentrada no filtro e aplicável a qualquer endpoint.

6. Boas Práticas e Armadilhas#

FaçaEvite
Centralizar validação repetida em um filtroRepetir if (dto is null) em cada ação
Curto-circuitar via context.ResultLançar exceção para controlar fluxo comum
Aplicar o filtro só onde faz sentidoAplicar globalmente e afetar GETs sem DTO
Atenção

um filtro de validação global aplicado a ações sem DTO (GETs) apenas adiciona overhead. Prefira o escopo de ação/controller para endpoints de escrita.

7. Segurança e Produção#

  • Validar cedo e curto-circuitar economiza processamento e reduz superfície de erro.

8. Exercícios#

  • Fácil: aplique o filtro ao endpoint de PUT.
  • Médio: faça o filtro também rejeitar coleções vazias.
  • Desafio: transforme o filtro numa versão assíncrona (IAsyncActionFilter) e compare.

9. Resumo#

Extraímos a validação recorrente para um Action Filter reutilizável que curto-circuita requisições inválidas, deixando os controllers enxutos e a validação consistente.

10. Próximos Passos#

Módulo 30: paginação para lidar com grandes coleções.

11. Referências#

29-02 — Validação e refatoração com filters | Curso ASP.NET Core