← ASP.NET Core: aplicações, contratos e operação
03 / 10 · 60 MIN

Rotas, binding e validação

Identifica a origem dos argumentos e a fase que rejeita o pedido, separando correspondência da rota, conversão e regras de validação.

Três fronteiras antes do efeito

Routing decide que endpoint corresponde ao pedido. Binding obtém valores das origens declaradas ou inferidas e converte-os para os tipos da assinatura. Validação verifica regras sobre valores e modelos já representáveis. O handler de negócio não deve ser tratado como se todas estas falhas nascessem dentro dele.

Considera um pedido POST com Content-Type text/plain para um DTO JSON, outro com JSON mal formado e outro com JSON válido mas Quantity=0. A primeira falha pode ser 415; a segunda, 400 de binding; a terceira, 400 de validação se o mecanismo estiver ativo. O mesmo estado 400 não significa a mesma causa.

Constraints selecionam rotas

A rota /items/{id:int} só corresponde se o segmento satisfizer a constraint int. Sem outra rota ou tratamento próprio, /items/blue não chega ao handler e produz 404. Uma resposta que o handler teria produzido para um id inválido não participa, porque o endpoint nem foi selecionado.

Quando o contrato exige um erro de entrada 400 para esse segmento, separa a seleção da validação. Uma rota /items/{id} com binding int permite rejeitar uma conversão inválida nessa fronteira; um tratamento explícito pode definir os detalhes públicos. Mantém distinta a pesquisa de um id numérico válido que não existe.

A origem faz parte do contrato

FromRoute, FromQuery, FromHeader e FromBody tornam explícita a origem. FromQuery(Name="p") permite que a variável C# se chame page enquanto o cliente envia p. Isto evita depender de uma coincidência de nomes e torna alterações do contrato visíveis na assinatura.

A inferência também considera o tipo: um tipo complexo registado como serviço pode ser obtido por DI em vez de ser lido do corpo. Se SearchRequest deve representar o JSON do cliente, FromBody exprime essa intenção. Não tentes corrigir uma origem inferida mudando apenas o nome do endpoint ou um cabeçalho sem relação com DI.

Ausência não é texto inválido

Um int? permite representar ausência. No exemplo, se p não existir na query, page é null e page ?? 1 escolhe o valor predefinido. Se p=blue estiver presente, o valor não é convertível num inteiro; o nullable não significa que qualquer texto inválido será silenciosamente substituído por null.

Esta diferença protege o contrato: um cliente que omite uma opção pode aceitar o comportamento predefinido, enquanto um cliente que envia dados mal formados precisa de corrigir o pedido. A expressão de fallback é executada no handler, depois do binding. Mudar o fallback não corrige uma falha que impede essa chamada.

Conservar a multiplicidade

A query /search?tag=urgent&tag=fragile contém dois valores para a mesma chave. Um parâmetro string[] tag conserva essa multiplicidade. Não transfiras estes dados para FromBody ou FromHeader sem também alterar o contrato que o cliente usa; os atributos não são formas equivalentes de pedir o mesmo valor.

Também não assumas que uma única string urgent,fragile é automaticamente igual a duas ocorrências da chave. O contrato deve declarar como cada valor é enviado e interpretado. No exemplo, a resposta mostra o array recebido para facilitar a leitura do binding; não faz uma pesquisa real nem concede acesso aos objetos associados às etiquetas.

Ativar a validação do modelo

Range(1,100) no DTO declara uma regra, mas a sua execução depende da infraestrutura. Em ASP.NET Core 10, AddValidation ativa a validação integrada dos parâmetros suportados. O gerador precisa de descobrir os modelos; o exemplo mantém modelo, endpoint e chamada de registo na assembly da aplicação e assume metadata gerada.

Se o registo for deslocado para outra assembly, revê a descoberta em vez de presumir cobertura de todos os tipos. DisableValidation desativa o mecanismo para um endpoint específico. Estas regras não substituem autorização nem validação dependente de estado atual, como stock disponível. Também são distintas da validação de opções no arranque da aula anterior.

Diagnosticar com pedidos delimitados

Lê o exemplo como um modelo: /items/42?p=3 produz id=42 e page=3; sem p, page=1. /items/42?p=blue falha antes da resposta do handler. Para POST /requests com JSON legível, Quantity=0 é rejeitado pela regra ativa, enquanto Quantity=3 permite valid-in-model. Este resultado não confirma persistência ou entrega.

Para cada registo, escolhe a primeira fronteira que impede a execução e a alteração mínima que corrige o contrato. Não removas a validação para esconder um erro de cliente. As avaliações apresentam pedidos e observações ilustrativos para seleção de respostas; não exigem executar o código nem recolher tráfego.

// Program.cs: ASP.NET Core 10.0 Web SDK, net10.0, ImplicitUsings enabled.
// Microsoft.Extensions.Validation 10.x available; model and AddValidation
// are in this application assembly, with generated validation metadata.
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddValidation();
var app = builder.Build();
app.MapGet("/items/{id}", (int id, [FromQuery(Name = "p")] int? page) =>
    TypedResults.Ok(new { id, page = page ?? 1 }));
app.MapGet("/search", ([FromQuery] string[] tag) =>
    TypedResults.Ok(new { tags = tag }));
app.MapPost("/requests", ([FromBody] WorkRequest request) =>
    TypedResults.Ok(new { request.Quantity, state = "valid-in-model" }));
app.Run();

public sealed class WorkRequest
{
    [Range(1, 100)]
    public int Quantity { get; set; }
}
NA PRÁTICA

Em /items/42?p=3, id vem do caminho e page da query p. Omitir p usa 1; p=blue falha a conversão. No POST JSON, Quantity=0 viola Range; Quantity=3 permite a resposta ilustrativa. Não é criada uma encomenda.

Armadilhas comuns

Usar constraints como validação de entrada; assumir que nullable aceita qualquer texto; perder parâmetros repetidos; depender da inferência depois de registar um DTO em DI; colocar anotações sem ativar a validação correspondente.

Tópicos relacionados: Alojamento, middleware e percurso do pedido · Respostas, erros e contratos de API · Autenticação e autorização

Leva esta ideia contigo

Primeiro seleciona o endpoint; depois identifica e converte os dados; finalmente aplica as regras de aceitação. Uma falha em cada fronteira tem significado e correção próprios.

Criar conta

Referência: Explicit parameter binding · ASP.NET Core 10.0 / .NET 10 / C# 14