Pular para o conteúdo
.NETModel binding na API
Módulo 04CRUD Completo e Validação

Model binding na API

avancado 25 min de leitura·Atualizado · .NET 9
Resumo

Model binding mapeia dados da requisição (rota, query string, corpo, cabeçalhos) para os parâmetros da ação. Quando o formato não é padrão — como ids=1,2,3 — implementamos um model binder customizado.

1. Objetivos de Aprendizagem#

  • Explicar as fontes de binding e os atributos [FromRoute], [FromQuery], [FromBody], [FromHeader].
  • Implementar um IModelBinder para converter uma string de ids em coleção tipada.
  • Registrar e aplicar o binder customizado.

2. Pré-requisitos#

  • Criação de coleção (tópico 23.2).

3. Conceito#

O ASP.NET Core resolve os parâmetros da ação a partir de várias fontes. Com [ApiController], a inferência é automática: tipos complexos vêm do corpo, tipos simples da rota/query. Quando precisamos de um formato especial (uma lista separada por vírgulas na URL), escrevemos um binder customizado implementando IModelBinder.

4. Mão na Massa#

4.1. Setup#

Sem pacotes extras.

4.2. Implementação Passo a Passo#

  1. Binder para IEnumerable<Guid> a partir de "1,2,3":
C#
using Microsoft.AspNetCore.Mvc.ModelBinding;

public class ArrayModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (!bindingContext.ModelMetadata.IsEnumerableType)
        {
            bindingContext.Result = ModelBindingResult.Failed();
            return Task.CompletedTask;
        }

        var provided = bindingContext.ValueProvider
            .GetValue(bindingContext.ModelName).ToString();

        if (string.IsNullOrWhiteSpace(provided))
        {
            bindingContext.Result = ModelBindingResult.Success(null);
            return Task.CompletedTask;
        }

        var guids = provided.Split(',', StringSplitOptions.RemoveEmptyEntries)
            .Select(s => Guid.Parse(s.Trim()))
            .ToArray();

        bindingContext.Result = ModelBindingResult.Success(guids);
        return Task.CompletedTask;
    }
}
  1. Aplique com [ModelBinder]:
C#
[HttpGet("colecao/{ids}", Name = "ProdutoCollection")]
public async Task<IActionResult> GetPorIds(
    [ModelBinder(BinderType = typeof(ArrayModelBinder))] IEnumerable<Guid> ids)
{
    var produtos = await _service.Produto.GetByIdsAsync(ids, trackChanges: false);
    return Ok(produtos);
}

4.3. Executando#

Shell
curl http://localhost:5000/api/produtos/colecao/{id1},{id2}

5. Exemplo Completo#

Fluxo completo: POST colecao (9.2) retorna Location com ids=...; GET colecao/{ids} usa o ArrayModelBinder para materializar a lista e buscar os recursos.

6. Boas Práticas e Armadilhas#

FaçaEvite
Validar/tratar entradas malformadas no binderDeixar Guid.Parse lançar exceção não tratada
Usar binder só quando o formato padrão não bastaReimplementar binding que o framework já faz
Limitar a quantidade de ids aceitosAceitar milhares de ids numa URL
Atenção

Guid.Parse lança em entrada inválida. Prefira Guid.TryParse e retorne 400 de forma controlada para não vazar exceções.

7. Segurança e Produção#

  • URLs muito longas (muitos ids) podem estourar limites do servidor/proxy. Considere POST com corpo para lotes grandes.

8. Exercícios#

  • Fácil: troque Guid.Parse por TryParse e falhe graciosamente.
  • Médio: limite o binder a 50 ids.
  • Desafio: generalize o binder para IEnumerable<T> usando TypeConverter.

9. Resumo#

Model binding conecta a requisição aos parâmetros da ação; um IModelBinder customizado resolve formatos não padrão como listas separadas por vírgula, com validação segura de entrada.

10. Próximos Passos#

Módulo 24: requisições DELETE, incluindo remoção de pai com filhos.

11. Referências#

23-03 — Model binding na API | Curso ASP.NET Core