Middleware no ASP.NET Core: Entendendo o Pipeline Completo da Aplicação

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
   ↑
Response

Perceba 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.Items

Exemplo:

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 /products

O log exibirá algo semelhante:

Endpoint: /products - Tempo: 503 ms

Esse 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.

Confira mais:

Fique por dentro das novidades

Assine nossa newsletter e receba as últimas atualizações e artigos diretamente em seu email.

Assinar gratuitamente