0Pricing
C# Academy · Aula

Escrevendo middleware personalizado

Crie middleware embutido com Use/Run/Map e middleware baseado em classes com InvokeAsync para componentes reutilizáveis.

Escrevendo middleware personalizado é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.

Por que usar componentes intermediários personalizados?

Componentes intermediários personalizados lidam com preocupações transversais aplicáveis a muitas requisições: registro, medição de tempo, tratamento de erros, autenticação, compactação e armazenamento em cache. Escrever essa lógica uma vez faz com que ela seja executada automaticamente para toda requisição correspondente.

Componente intermediário embutido com Use

A maneira mais rápida de adicionar um componente intermediário: passe um delegado para app.Use(). É uma boa opção para prototipagem ou lógica realmente simples.

app.Use(async (context, next) =>
{
    var start = DateTimeOffset.UtcNow;

    await next(context);

    var elapsed = DateTimeOffset.UtcNow - start;
    context.Response.Headers.Append(
        "X-Elapsed", elapsed.TotalMilliseconds.ToString("F0") + "ms");
});

Componente intermediário baseado em classe, por convenção

Uma classe convencional de componente intermediário tem um construtor que recebe RequestDelegate e um método público InvokeAsync. Parâmetros adicionais do construtor podem ser injetados pelo DI.

public class SecurityHeadersMiddleware
{
    private readonly RequestDelegate _next;

    public SecurityHeadersMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        var headers = context.Response.Headers;
        headers.Append("X-Content-Type-Options", "nosniff");
        headers.Append("X-Frame-Options", "DENY");
        headers.Append("X-XSS-Protection", "1; mode=block");
        headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");

        await _next(context);
    }
}

// Extension method for clean registration:
public static class SecurityHeadersExtensions
{
    public static IApplicationBuilder UseSecurityHeaders(
        this IApplicationBuilder app) =>
        app.UseMiddleware<SecurityHeadersMiddleware>();
}

IMiddleware para dependências com escopo do DI

Se o seu componente intermediário precisar de serviços com escopo, como DbContext, implemente IMiddleware. Registre-o com escopo, e a estrutura o resolverá novamente a cada requisição.

public class AuditMiddleware : IMiddleware
{
    private readonly AuditDbContext _db;
    private readonly IHttpContextAccessor _http;

    public AuditMiddleware(AuditDbContext db, IHttpContextAccessor http)
    {
        _db = db;
        _http = http;
    }

    public async Task InvokeAsync(HttpContext ctx, RequestDelegate next)
    {
        await next(ctx);

        if (ctx.Request.Method != "GET")
        {
            _db.AuditLogs.Add(new AuditLog
            {
                User   = ctx.User.Identity?.Name,
                Path   = ctx.Request.Path,
                Status = ctx.Response.StatusCode,
                At     = DateTime.UtcNow
            });
            await _db.SaveChangesAsync();
        }
    }
}

builder.Services.AddScoped<AuditMiddleware>();
app.UseMiddleware<AuditMiddleware>();

Componentes intermediários com opções

Passe a configuração para o componente intermediário por meio de um objeto de opções no construtor. Registre as opções no contêiner de DI ou passe-as diretamente ao registrar o componente intermediário.

public class ThrottleOptions
{
    public int MaxRequestsPerSecond { get; set; } = 100;
    public string[] ExcludedPaths { get; set; } = Array.Empty<string>();
}

public class ThrottleMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ThrottleOptions _options;

    public ThrottleMiddleware(RequestDelegate next, ThrottleOptions options)
    {
        _next   = next;
        _options = options;
    }
    // ...
}

// Registration with options:
app.UseMiddleware<ThrottleMiddleware>(new ThrottleOptions
{
    MaxRequestsPerSecond = 50
});

Componente intermediário para tratamento de exceções

Um componente intermediário personalizado para tratamento de exceções captura todas as exceções não tratadas e retorna respostas de erro estruturadas.

public class GlobalExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalExceptionMiddleware> _logger;

    public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> l)
    {
        _next = next;
        _logger = l;
    }

    public async Task InvokeAsync(HttpContext ctx)
    {
        try { await _next(ctx); }
        catch (NotFoundException ex)
        {
            ctx.Response.StatusCode = 404;
            await ctx.Response.WriteAsJsonAsync(new { error = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unhandled exception");
            ctx.Response.StatusCode = 500;
            await ctx.Response.WriteAsJsonAsync(new { error = "Internal server error" });
        }
    }
}

Componente intermediário para registro de requisições

Um componente intermediário estruturado de registro de requisições e respostas registra o método, o caminho, o código de status e o tempo decorrido de cada requisição.

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestLoggingMiddleware> _log;

    public RequestLoggingMiddleware(RequestDelegate n, ILogger<RequestLoggingMiddleware> l)
    { _next = n; _log = l; }

    public async Task InvokeAsync(HttpContext ctx)
    {
        var sw = System.Diagnostics.Stopwatch.StartNew();
        await _next(ctx);
        sw.Stop();

        _log.LogInformation(
            "{Method} {Path} -> {Status} in {Ms}ms",
            ctx.Request.Method,
            ctx.Request.Path,
            ctx.Response.StatusCode,
            sw.ElapsedMilliseconds);
    }
}

Componente intermediário condicional com UseWhen

UseWhen cria uma ramificação condicional no fluxo de processamento com base em um predicado, sem dividi-lo permanentemente. Depois, a ramificação se reúne novamente ao fluxo principal.

// Apply authentication middleware only to /api/* routes
app.UseWhen(
    ctx => ctx.Request.Path.StartsWithSegments("/api"),
    apiApp =>
    {
        apiApp.UseAuthentication();
        apiApp.UseAuthorization();
    });

// Public routes (/public/*) bypass authentication
app.MapGet("/public/health", () => "OK");
app.MapGet("/api/data", [Authorize] async (DataService s) => await s.GetAsync());

Componente intermediário de armazenamento de respostas em cache

O componente intermediário integrado de armazenamento de respostas em cache guarda respostas completas na memória. Configure políticas de cache por ponto de extremidade usando cabeçalhos ou atributos.

builder.Services.AddResponseCaching();

app.UseResponseCaching();

app.MapGet("/products", async (AppDbContext db) =>
{
    var products = await db.Products.AsNoTracking().ToListAsync();
    return Results.Ok(products);
})
.CacheOutput(p => p.Expire(TimeSpan.FromMinutes(2)).Tag("products"));

Na prática: componente intermediário para modo de manutenção

Um componente intermediário de modo de manutenção que lê um sinalizador da configuração, com suporte à recarga a quente por meio de IOptionsMonitor, e rejeita requisições que não sejam verificações de integridade durante a manutenção.

public class MaintenanceMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IOptionsMonitor<MaintenanceOptions> _options;

    public MaintenanceMiddleware(RequestDelegate next,
        IOptionsMonitor<MaintenanceOptions> opts)
    { _next = next; _options = opts; }

    public async Task InvokeAsync(HttpContext ctx)
    {
        if (_options.CurrentValue.IsEnabled
            && !ctx.Request.Path.StartsWithSegments("/health"))
        {
            ctx.Response.StatusCode = 503;
            ctx.Response.Headers.Append("Retry-After", "300");
            await ctx.Response.WriteAsJsonAsync(
                new { message = "Service under maintenance" });
            return;
        }
        await _next(ctx);
    }
}

Verificação rápida

Por que você deve implementar IMiddleware em vez da abordagem baseada em convenção quando precisar de um serviço com escopo, como DbContext?

Recapitulação: criação de componentes intermediários personalizados

Principais conclusões:

  • Em linha, com um delegado Use: rápido, para uma única linha; baseado em classe: reutilizável e testável
  • Classe convencional: recebe RequestDelegate no construtor; InvokeAsync(HttpContext)
  • IMiddleware: resolução de DI por requisição — necessária para dependências com escopo
  • UseWhen: ramificação condicional que se reúne novamente ao fluxo principal
  • Escreva primeiro o componente intermediário de tratamento de exceções, o mais externo, para capturar todos os erros
  • Crie métodos de extensão, como UseXxx, para um registro claro e fácil de localizar

Perguntas Frequentes

A aula “Escrevendo middleware personalizado” é grátis?

Sim — o texto completo de “Escrevendo middleware personalizado” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.

O que vou aprender em “Escrevendo middleware personalizado”?

Crie middleware embutido com Use/Run/Map e middleware baseado em classes com InvokeAsync para componentes reutilizáveis. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar C# Academy?

Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Escrevendo middleware personalizado”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de C# Academy?

Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Visão geral do pipeline do ASP.NET Core
  2. Escrevendo middleware personalizado
  3. Interrupção antecipada e ramificação
  4. Ordenação do middleware e middleware integrado
← Voltar para C# Academy