Middleware do ASP.NET Core
ResumoTodo request no ASP.NET Core passa por um pipeline de componentes chamados middleware. Entender esse pipeline — e a ordem dele — é a base para tudo: autenticação, logging, tratamento de erros e roteamento.
1. Objetivos de Aprendizagem#
- Explicar o pipeline de requisição e o conceito de
next. - Escrever um middleware inline com
Use. - Usar
Run,MapeMapWhenpara ramificar o pipeline.
2. Pré-requisitos#
Program.csfuncional (tópicos anteriores).
3. Conceito#
O diagrama abaixo resume o fluxo principal.
Um middleware é um componente que recebe o HttpContext e decide: processar e chamar o próximo (await next()), ou curto-circuitar (responder sem chamar o próximo). O pipeline é uma cadeia — a ordem de registro é a ordem de execução na entrada e a ordem inversa na saída.
O porquê de conhecer isso: 90% dos bugs de "meu UseAuthorization não funciona" são problemas de ordem no pipeline.
4. Mão na Massa#
4.1. Setup#
Nenhum pacote. Vamos escrever middleware inline no Program.cs.
4.2. Implementação Passo a Passo#
Use— processa e continua o pipeline:
app.Use(async (context, next) =>
{
Console.WriteLine($"→ {context.Request.Method} {context.Request.Path}");
await next(context);
Console.WriteLine($"← {context.Response.StatusCode}");
});
Run— terminal, não chamanext:
app.Run(async context =>
{
await context.Response.WriteAsync("Pipeline terminal.");
});
Map— ramifica por caminho:
app.Map("/healthz", branch =>
{
branch.Run(async context => await context.Response.WriteAsync("OK"));
});
MapWhen— ramifica por predicado sobre o request:
app.MapWhen(
context => context.Request.Query.ContainsKey("debug"),
branch => branch.Run(async context =>
await context.Response.WriteAsync("Ramo de debug")));
4.3. Executando#
dotnet run
Acesse /healthz e /qualquer?debug=1 e observe cada ramo responder de forma diferente.
5. Exemplo Completo#
var app = builder.Build();
app.Use(async (context, next) =>
{
var sw = System.Diagnostics.Stopwatch.StartNew();
await next(context);
sw.Stop();
context.Response.Headers["X-Elapsed-ms"] = sw.ElapsedMilliseconds.ToString();
});
app.Map("/healthz", b => b.Run(async c => await c.Response.WriteAsync("OK")));
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
| Registrar middleware na ordem correta (erros → auth → routing) | Colocar autenticação depois do roteamento dos controllers |
Chamar await next(context) quando não for terminal | Esquecer o next e curto-circuitar sem querer |
| Extrair middleware complexo para uma classe dedicada | Acumular lógica pesada inline no Program.cs |
Atençãonão escreva no corpo da resposta e depois chame
nextesperando alterar o status — uma vez que a resposta começou (HasStarted), cabeçalhos e status não podem mais mudar.
7. Segurança e Produção#
- O middleware de tratamento de erros deve ser o primeiro para capturar exceções de todos os componentes seguintes.
- Middleware que loga o corpo do request deve ter cuidado com PII/LGPD (ver Módulo 16).
8. Exercícios#
- Fácil: escreva um middleware que adicione o cabeçalho
X-Request-Id. - Médio: transforme o middleware de cronômetro numa classe convencional (
InvokeAsync) e registre comUseMiddleware<T>(). - Desafio: use
MapWhenpara direcionar requests comAccept: text/plaina um ramo que responde em texto puro.
9. Resumo#
O pipeline é uma cadeia ordenada de middleware. Use continua, Run finaliza, Map/MapWhen ramificam. A ordem de registro define o comportamento.
10. Próximos Passos#
Módulo 16: um serviço de logging desacoplado por interface, injetado via DI.
11. Referências#
- Microsoft Learn — Middleware do ASP.NET Core
- Microsoft Learn — Ordem do middleware
- Microsoft Learn — Escrever middleware personalizado