Middleware no ASP.NET Core: Entendendo o Pipeline Completo da Aplicação
Entenda como funciona o pipeline de requisições do ASP.NET Core e descubra por que os middlewares são fundamentais para autenticação, logs, segurança, tratamento de erros e muito mais.
Se existe um conceito fundamental dentro do ASP.NET Core, ele é o Middleware. Independentemente de você estar construindo uma API REST, uma Minimal API, um sistema MVC ou até mesmo aplicações em tempo real com SignalR, o pipeline de middlewares com certeza vai estar presente em todas as requisições.
Muitos desenvolvedores utilizam middlewares diariamente muitas vezes sem perceber. Recursos como autenticação, autorização, tratamento de exceções, logs, compressão de resposta e CORS são implementados justamente através desse mecanismo.
Entender como o pipeline funciona é essencial para criar aplicações mais organizadas, performáticas e fáceis de manter.
O que é um Middleware?
Middleware é um componente responsável por interceptar uma requisição HTTP durante sua passagem pela aplicação.
Ele atua como uma etapa intermediária entre o cliente e o endpoint final.
Quando uma requisição chega ao servidor, ela não é enviada diretamente para um Controller ou Endpoint. Antes disso, ela percorre uma sequência de componentes conhecidos como pipeline de middlewares.
Cada middleware pode:
- Executar alguma lógica antes da requisição continuar.
- Interromper o fluxo.
- Modificar a requisição.
- Modificar a resposta.
- Executar lógica após a execução dos próximos componentes.
Visualmente, o fluxo funciona assim:
Request
↓
Middleware A
↓
Middleware B
↓
Middleware C
↓
Endpoint
↑
Middleware C
↑
Middleware B
↑
Middleware A
↑
ResponsePerceba que o caminho de ida e volta passa pelos mesmos componentes.
Esse comportamento é conhecido como Pipeline Pattern.
Por que o ASP.NET Core utiliza Middlewares?
Antes do ASP.NET Core, a maioria das funcionalidades eram acopladas diretamente ao IIS e ao próprio framework.
Com a chegada do ASP.NET Core, a Microsoft adotou uma arquitetura modular onde cada funcionalidade pode ser adicionada ou removida individualmente conforme a sua necessidade.
Isso trouxe uma serie de benefícios importantes:
- Menor consumo de recursos.
- Melhor performance.
- Maior flexibilidade.
- Pipeline totalmente configurável.
- Facilidade para criação de componentes personalizados.
Na prática, sua aplicação carrega apenas aquilo que realmente precisa durante a execução.
Como funciona o Pipeline de Requisições?
O pipeline é construído dentro do arquivo Program.cs.
Exemplo:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();A ordem é extremamente importante.
Cada middleware executa exatamente na sequência em que foi registrado.
Uma configuração incorreta pode gerar problemas difíceis de identificar.
Por exemplo:
app.UseAuthorization();
app.UseAuthentication();Nesse caso a autorização será executada antes da autenticação, o que fará com que o usuário nunca seja identificado corretamente.
O Delegate RequestDelegate
Internamente, todo middleware trabalha sobre um objeto chamado RequestDelegate.
Sua assinatura é simples:
public delegate Task RequestDelegate(HttpContext context);Esse delegate representa o próximo middleware da cadeia.
Sempre que chamamos:
await next(context);estamos encaminhando a execução para o próximo componente do pipeline.
O Objeto HttpContext
O HttpContext representa toda a requisição atual.
Através dele podemos acessar:
context.Request
context.Response
context.User
context.Session
context.ItemsExemplo:
var ip = context.Connection.RemoteIpAddress;
var path = context.Request.Path;Praticamente todos os middlewares trabalham manipulando informações presentes no HttpContext.
Principais Métodos de Configuração
Use()
Permite continuar o pipeline.
app.Use(async (context, next) =>
{
Console.WriteLine("Antes");
await next();
Console.WriteLine("Depois");
});É o método mais comum para construção de middlewares.
Run()
Encerra o pipeline.
app.Run(async context =>
{
await context.Response.WriteAsync("Fim do pipeline");
});Nenhum middleware após esse será executado.
Map()
Cria ramificações no pipeline.
app.Map("/admin", admin =>
{
admin.Run(async context =>
{
await context.Response.WriteAsync("Área administrativa");
});
});MapWhen()
Executa um pipeline alternativo baseado em condições.
app.MapWhen(
context => context.Request.Query.ContainsKey("debug"),
branch =>
{
branch.Run(async context =>
{
await context.Response.WriteAsync("Modo Debug");
});
});Principais Middlewares Nativos
O ASP.NET Core possui diversos middlewares prontos.
Exception Handler
Tratamento global de exceções.
app.UseExceptionHandler("/error");Evita exposição de detalhes internos da aplicação.
HTTPS Redirection
Redireciona HTTP para HTTPS.
app.UseHttpsRedirection();Fundamental para segurança.
Static Files
Permite servir arquivos estáticos.
app.UseStaticFiles();Utilizado para:
- CSS
- JavaScript
- Imagens
- PDFs
Routing
Responsável por localizar endpoints.
app.UseRouting();Authentication
Realiza autenticação.
app.UseAuthentication();Authorization
Valida permissões.
app.UseAuthorization();CORS
Controla acesso entre domínios.
app.UseCors();Muito utilizado em APIs consumidas por aplicações frontend.
Response Compression
Comprime respostas HTTP.
app.UseResponseCompression();Onde Utilizar Middlewares?
Middlewares são ideais para funcionalidades transversais, também chamadas de Cross-Cutting Concerns.
Exemplos:
- Logging
- Auditoria
- Monitoramento
- Segurança
- Autenticação
- Rate Limiting
- Tratamento de exceções
- Cache
- Compressão
- Métricas
- Rastreamento de requisições
Sempre que uma funcionalidade precisa ocorrer em várias rotas, middleware costuma ser uma excelente escolha.
Onde NÃO Utilizar?
Nem tudo deve ser middleware.
Evite quando:
Existe regra de negócio
Errado:
if(cliente.LimiteCredito < valor)Esse tipo de validação pertence ao domínio.
Lógica específica de um endpoint
Se apenas uma rota utiliza determinada regra, ela provavelmente deve ficar no endpoint ou service.
Operações pesadas
Middlewares executam em todas as requisições.
Consultas desnecessárias ao banco podem impactar significativamente a performance.
Vantagens
Reutilização
Uma única implementação atende toda aplicação.
Organização
Cada responsabilidade fica isolada.
Manutenção simplificada
Alterações são centralizadas.
Baixo acoplamento
Os componentes não dependem uns dos outros.
Alta extensibilidade
Novos comportamentos podem ser adicionados facilmente.
Desvantagens
Ordem de execução crítica
Um posicionamento incorreto pode gerar falhas.
Debug mais complexo
À medida que o pipeline cresce, rastrear problemas se torna mais difícil.
Impacto em performance
Middlewares excessivos aumentam o tempo de processamento.
Possibilidade de responsabilidades incorretas
Muitos desenvolvedores acabam colocando regras de negócio dentro do pipeline.
Principais Bibliotecas Relacionadas
Diversas bibliotecas populares utilizam middlewares internamente.
Serilog
Logs estruturados.
app.UseSerilogRequestLogging();Swagger
Documentação de APIs.
app.UseSwagger();
app.UseSwaggerUI();Polly
Resiliência e retry.
Frequentemente utilizado em conjunto com HttpClient.
AspNetCoreRateLimit
Controle de limite de requisições.
Protege APIs contra abuso.
Health Checks
Monitoramento de saúde da aplicação.
app.MapHealthChecks("/health");OpenTelemetry
Observabilidade distribuída.
Integração com Grafana, Jaeger e Prometheus.
Problemas que Middleware Resolve
Imagine uma API com 50 endpoints.
Sem middleware:
_logger.LogInformation(...);
try
{
}
catch
{
}Repetido em todos os endpoints.
Além da duplicação, a manutenção se torna difícil.
Com middleware:
app.UseMiddleware<GlobalExceptionMiddleware>();Todo tratamento fica centralizado.
Exemplo Prático com Minimal API
Vamos criar um middleware que registra tempo de execução das requisições.
Middleware
public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestTimingMiddleware> _logger;
public RequestTimingMiddleware(
RequestDelegate next,
ILogger<RequestTimingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var stopwatch = Stopwatch.StartNew();
await _next(context);
stopwatch.Stop();
_logger.LogInformation(
"Endpoint: {Path} - Tempo: {Elapsed} ms",
context.Request.Path,
stopwatch.ElapsedMilliseconds);
}
}Extensão
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseRequestTiming(
this IApplicationBuilder app)
{
return app.UseMiddleware<RequestTimingMiddleware>();
}
}Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
var app = builder.Build();
app.UseRequestTiming();
app.MapGet("/products", async () =>
{
await Task.Delay(500);
return Results.Ok(new[]
{
"Notebook",
"Mouse",
"Teclado"
});
});
app.Run();Resultado
Ao acessar:
GET /productsO log exibirá algo semelhante:
Endpoint: /products - Tempo: 503 msEsse exemplo demonstra um cenário extremamente comum em ambientes corporativos: monitoramento de desempenho de requisições.
A partir dessa base seria possível evoluir para:
- Auditoria completa.
- Correlation ID.
- Métricas Prometheus.
- OpenTelemetry.
- Distributed Tracing.
- Monitoramento de APIs em produção.
Conclusão
Middleware é um dos pilares arquiteturais do ASP.NET Core. Ele permite construir aplicações modulares, desacopladas e altamente configuráveis através de um pipeline de processamento de requisições. Recursos essenciais como autenticação, autorização, logs, tratamento de erros, compressão e monitoramento são implementados sobre esse conceito.
Dominar o pipeline significa entender exatamente como cada requisição percorre sua aplicação. Esse conhecimento permite criar APIs mais robustas, melhorar a observabilidade do sistema, reduzir duplicação de código e implementar funcionalidades transversais de forma elegante. Em aplicações modernas construídas com Minimal APIs, MVC ou microserviços, conhecer profundamente os middlewares deixou de ser um diferencial e passou a ser um requisito fundamental para qualquer desenvolvedor ASP.NET Core.
Código-fonte do projeto
Para facilitar o entendimento, disponibilizei o projeto completo com o exemplo de Middleware, já organizado com separação de responsabilidades e boas práticas:
👉 Baixar o projeto no GitHub neste link:
Quer ver mais conteúdos como este?
Se você trabalha com .NET, C# e backend, este blog seguirá trazendo conteúdos práticos e objetivos sobre o ecossistema Microsoft, com foco em código, boas práticas e decisões técnicas aplicadas ao mundo real.
Acompanhe para continuar aprofundando seu domínio sobre a plataforma .NET.