Partilhar via


ASP.NET Middleware principal

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.

Advertência

Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.

Importante

Estas informações referem-se a um produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado comercialmente. A Microsoft não oferece garantias, expressas ou implícitas, em relação às informações fornecidas aqui.

Para a versão atual, consulte a versão .NET 9 deste artigo.

Por Rick Anderson e Steve Smith

Middleware é um software montado em um pipeline de aplicativos para lidar com solicitações e respostas. Cada componente:

  • Escolhe se deseja passar a solicitação para o próximo componente no pipeline.
  • Pode executar tarefas antes e depois do próximo componente na cadeia de processos.

Os delegados de solicitação são usados para criar o pipeline de solicitação. Os delegados de solicitação lidam com cada solicitação HTTP.

Os delegados de solicitação são configurados usando os métodos de extensão Run, Mape Use. Um delegado de solicitação individual pode ser especificado em linha como um método anônimo (chamado middleware in-line) ou pode ser definido em uma classe reutilizável. Essas classes reutilizáveis e métodos anônimos em linha são middleware, também chamados de componentes de middleware . Cada componente de middleware no pipeline de solicitação é responsável por invocar o próximo componente no pipeline ou curto-circuitar o pipeline. Quando um middleware entra em curto-circuito, é chamado de middleware de terminal porque impede que outros middleware processem a solicitação.

Migrar manipuladores e módulos HTTP para middleware do ASP.NET Core explica a diferença entre os fluxos de execução de pedidos no ASP.NET Core e no ASP.NET 4.x e fornece exemplos adicionais de middleware.

A função do middleware por tipo de aplicativo

Blazor Web Apps, Razor Pages e MVC processam solicitações de navegador no servidor com middleware. As orientações neste artigo aplicam-se a estes tipos de aplicações.

Os aplicativos Blazor WebAssembly autônomos são executados inteiramente no cliente e não processam solicitações com um pipeline de middleware. As orientações neste artigo não se aplicam a aplicativos Blazor WebAssembly autônomos.

Análise de código de middleware

ASP.NET Core inclui muitos analisadores de plataforma de compilador que inspecionam o código do aplicativo quanto à qualidade. Para obter mais informações, consulte Análise de código em aplicativos ASP.NET Core

Crie um pipeline de middleware com WebApplication

O pipeline de solicitação ASP.NET Core consiste em uma sequência de delegados de solicitação, chamados um após o outro. O diagrama a seguir demonstra o conceito. O fio da execução segue as setas pretas.

Padrão de processamento de solicitação mostrando uma solicitação chegando, processando por meio de três middlewares e a resposta saindo do aplicativo. Cada middleware executa sua lógica e entrega a solicitação para o próximo middleware na instrução next(). Depois que o terceiro middleware processa a solicitação, a solicitação passa de volta pelos dois middlewares anteriores em ordem inversa para processamento adicional após suas instruções next() antes de sair do aplicativo como resposta ao cliente.

Cada delegado pode executar operações antes e depois do próximo delegado. Os delegados de tratamento de exceções devem ser chamados no início do pipeline, para que possam interceptar exceções que ocorrem em estágios posteriores do pipeline.

O aplicativo ASP.NET Core mais simples possível configura um único delegado de solicitação que lida com todas as solicitações. Este caso não inclui um pipeline de solicitação real. Em vez disso, uma única função anônima é chamada em resposta a cada solicitação HTTP.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello world!");
});

app.Run();

Encadeie vários delegados de solicitação junto com Use. O parâmetro next indica o próximo delegatário no pipeline. Você pode curto-circuitar o pipeline não chamando o parâmetro next. Geralmente, é possível realizar ações antes e depois do delegado next, como demonstra o exemplo a seguir:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

Encerramento rápido do pipeline de pedidos

Quando um delegado não passa uma solicitação para o próximo delegado, ele é chamado de curto-circuito pipeline de solicitação. O curto-circuito é muitas vezes desejável porque evita trabalho desnecessário. Por exemplo, o middleware de arquivo estático pode atuar como um middleware de terminal ao processar um pedido de um arquivo estático e interromper o rest do pipeline. O middleware adicionado ao pipeline antes do middleware que encerra o processamento adicional ainda processa o código após suas instruções next.Invoke. No entanto, veja o seguinte aviso sobre tentar escrever numa resposta que já foi enviada.

Advertência

Não ligue para next.Invoke durante ou após a resposta ter sido enviada ao cliente. Após o início de uma HttpResponse, as alterações resultam em uma exceção. Por exemplo, cabeçalhos de configuração e um código de status lançam uma exceção após o início da resposta. Escrevendo para o corpo de resposta depois de ligar para next:

  • Pode causar uma violação de protocolo, como escrever mais do que o Content-Lengthdeclarado.
  • Pode corromper o formato do corpo, como escrever um rodapé HTML em um arquivo CSS.

HasStarted é uma dica útil para indicar se os cabeçalhos foram enviados ou se o corpo foi gravado.

Para obter mais informações, consulte middleware de curto-circuito após o roteamento.

Run delegados

Os delegados Run não recebem um parâmetro next. O primeiro Run delegado é sempre terminal e encerra o pipeline. Run é uma convenção. Alguns componentes de middleware podem expor Run[Middleware] métodos que são executados no final do pipeline.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

Se quiser ver os comentários de código traduzidos para outros idiomas além do inglês, avise-nos nesta discussão do GitHub .

No exemplo anterior, o delegado Run grava "Hello from 2nd delegate." na resposta e, em seguida, encerra o pipeline. Se um delegado Use ou Run for adicionado após o delegado Run, ele não será chamado.

Prefira o aplicativo. Usar sobrecarga que requer passar o contexto para o próximo

A não alocação aplicativo. Use método de extensão:

  • Requer passar o contexto para next.
  • Poupa duas alocações internas por pedido que são necessárias quando se utiliza a outra sobrecarga.

Para mais informações, veja este problema do GitHub.

Ordem de middleware

O diagrama a seguir mostra o pipeline completo de processamento de solicitações para ASP.NET aplicativos Core MVC e Razor Pages. Você pode ver como, numa aplicação típica, os middlewares existentes são ordenados e onde os middlewares personalizados são adicionados. Você tem controle total sobre como reordenar middlewares existentes ou injetar novos middlewares personalizados conforme necessário para seus cenários.

ASP.NET Pipeline de middleware principal

O middleware Endpoint no diagrama anterior executa o pipeline de filtro para o tipo de aplicação correspondente — MVC ou Razor Pages.

O middleware Roteamento no diagrama anterior é mostrado depois de Arquivos estáticos. Esta é a ordem que os modelos de projeto implementam chamando explicitamente app.UseRouting. Se você não chamar app.UseRouting, o middleware Roteamento é executado no início do pipeline por padrão. Para obter mais informações, consulte roteamento .

Pipeline de filtros do ASP.NET Core

A ordem em que os componentes de middleware são adicionados no arquivo de Program.cs define a ordem em que os componentes de middleware são invocados nas solicitações e a ordem inversa para a resposta. A ordem é crítica para segurança, desempenho e funcionalidade.

O código realçado a seguir no Program.cs adiciona componentes de middleware relacionados à segurança na ordem recomendada típica:

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMiddleware.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
    ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();

app.UseRouting();
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

No código anterior:

  • Middleware que não é adicionado ao criar um novo aplicativo Web com contas de usuários individuais é comentado.
  • Nem todo middleware aparece nessa ordem exata, mas muitos aparecem. Por exemplo:
    • UseCors, UseAuthenticatione UseAuthorization devem aparecer na ordem mostrada.
    • UseCors atualmente deve surgir antes do UseResponseCaching. Este requisito é explicado em problema do GitHub dotnet/aspnetcore #23218.
    • UseRequestLocalization deve aparecer antes de qualquer middleware que possa verificar a cultura de solicitação, por exemplo, app.UseStaticFiles().
    • UseRateLimiter deve ser chamado após UseRouting quando APIs específicas de limite de taxa são usadas. Por exemplo, se o atributo [EnableRateLimiting] for usado, UseRateLimiter deverá ser chamado após UseRouting. Ao chamar apenas limitadores globais, UseRateLimiter pode ser chamado antes de UseRouting.

Em alguns cenários, o middleware pode ter uma ordenação diferente. Por exemplo, a ordem de cache e compactação é específica do cenário e há várias ordens válidas. Por exemplo:

app.UseResponseCaching();
app.UseResponseCompression();

Com o código anterior, o uso da CPU pode ser reduzido armazenando em cache a resposta compactada, mas você pode acabar armazenando em cache várias representações de um recurso usando diferentes algoritmos de compactação, como Gzip ou Brotli.

A seguinte ordenação combina arquivos estáticos para permitir o armazenamento em cache de arquivos estáticos compactados:

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

O código Program.cs a seguir adiciona componentes de middleware para cenários comuns de aplicativos:

  1. Tratamento de exceções/erros
    • Quando o aplicativo é executado no ambiente de desenvolvimento:
      • O Middleware da Página de Exceção do Desenvolvedor (UseDeveloperExceptionPage) relata erros de tempo de execução do aplicativo.
      • O middleware de página de erro de banco de dados (UseDatabaseErrorPage) relata erros de tempo de execução do banco de dados.
    • Quando o aplicativo é executado no ambiente de produção:
      • O Exception Handler Middleware (UseExceptionHandler) captura exceções lançadas nos seguintes middlewares.
      • HTTP Strict Transport Security Protocol (HSTS) Middleware (UseHsts) adiciona o cabeçalho Strict-Transport-Security.
  2. HTTPS Redirection Middleware (UseHttpsRedirection) redireciona solicitações HTTP para HTTPS.
  3. Static File Middleware (UseStaticFiles) retorna arquivos estáticos e interrompe o processamento adicional de solicitações.
  4. Cookie Policy Middleware (UseCookiePolicy) está em conformidade com a aplicação com os regulamentos do Regulamento Geral sobre a Proteção de Dados (RGPD) da UE.
  5. Middleware de roteamento (UseRouting) para rotear solicitações.
  6. O middleware de autenticação (UseAuthentication) tenta autenticar o usuário antes que ele tenha acesso a recursos seguros.
  7. O middleware de autorização (UseAuthorization) autoriza um usuário a acessar recursos seguros.
  8. O middleware de sessão (UseSession) estabelece e mantém o estado da sessão. Se a aplicação usar o estado da sessão, chame o Middleware de Sessão depois do Middleware de Política de Cookie e antes do Middleware MVC.
  9. Middleware de Roteamento de Ponto Final (UseEndpoints com MapRazorPages) para adicionar pontos de extremidade do Razor Pages ao pipeline de solicitação.
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseDatabaseErrorPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();

No código de exemplo anterior, cada método de extensão de middleware é exposto em WebApplicationBuilder através do namespace Microsoft.AspNetCore.Builder.

UseExceptionHandler é o primeiro componente de middleware adicionado ao pipeline. Portanto, o Exception Handler Middleware captura quaisquer exceções que ocorram em chamadas posteriores.

O Middleware de Ficheiros Estáticos é chamado no início do pipeline para que possa lidar com solicitações e interromper o processo sem passar pelos componentes restantes. O middleware de arquivo estático não fornece nenhuma verificação de autorização. Todos os arquivos servidos pelo Static File Middleware, incluindo aqueles sob wwwroot, estão disponíveis publicamente. Para obter uma abordagem para proteger arquivos estáticos, consulte Arquivos estáticos no ASP.NET Core.

Se a solicitação não for tratada pelo Middleware de Arquivo Estático, ela será passada para o Middleware de Autenticação (UseAuthentication), que executa a autenticação. A autenticação não provoca curto-circuito em solicitações não autenticadas. Embora o Middleware de Autenticação autentique as solicitações, a autorização (e rejeição) ocorre apenas depois que o MVC seleciona uma Página de Razor específica ou um controlador MVC e sua respectiva ação.

O exemplo a seguir demonstra uma ordem de middleware em que as solicitações de arquivos estáticos são tratadas pelo Static File Middleware antes do Response Compression Middleware. Os arquivos estáticos não são compactados com essa ordem de middleware. As respostas do Razor Pages podem ser compactadas.

// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();

app.UseRouting();

app.UseResponseCompression();

app.MapRazorPages();

Para obter informações sobre aplicativos de página única, consulte Visão geral de aplicativos de página única (SPAs) em ASP.NET Core.

Ordem de UseCors e UseStaticFiles

A ordem para chamar UseCors e UseStaticFiles depende do aplicativo. Para obter mais informações, consulte ordem UseCors e UseStaticFiles

Ordem do Middleware de Cabeçalhos Reencaminhados

O Middleware de Cabeçalhos Encaminhados deve ser executado antes de outros middleware. Essa ordenação garante que o middleware que depende das informações de cabeçalhos encaminhados possa consumir os valores de cabeçalho para processamento. Para executar o middleware de cabeçalhos encaminhados após o middleware de diagnóstico e tratamento de erros, consulte ordem de middleware de cabeçalhos encaminhados.

Ramificar a linha de processamento de middleware

As extensões Map são usadas como convenção para ramificar o pipeline. Map ramifica o pipeline de solicitação com base nas correspondências do caminho de solicitação fornecido. Se o caminho da solicitação começar com o caminho fornecido, a ramificação será executada.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1", HandleMapTest1);

app.Map("/map2", HandleMapTest2);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMapTest1(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

static void HandleMapTest2(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 2");
    });
}

A tabela a seguir mostra as solicitações e respostas de http://localhost:1234 usando o código anterior.

Solicitar Resposta
localhost:1234 Olá do delegado não associado ao Mapa.
localhost:1234/map1 Teste de Mapa 1
localhost:1234/map2 Teste de Mapa 2
localhost:1234/map3 Olá de um delegado que não está no mapa.

Quando Map é usado, os segmentos de caminho correspondentes são removidos do HttpRequest.Path e anexados ao HttpRequest.PathBase para cada solicitação.

Map suporta aninhamento, por exemplo:

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

Map também pode corresponder a vários segmentos ao mesmo tempo:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1/seg1", HandleMultiSeg);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMultiSeg(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

MapWhen ramifica o pipeline de solicitação com base no resultado do predicado dado. Qualquer predicado do tipo Func<HttpContext, bool> pode ser usado para mapear solicitações para uma nova ramificação do pipeline. No exemplo a seguir, um predicado é usado para detetar a presença de uma variável de cadeia de caracteres de consulta branch:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        var branchVer = context.Request.Query["branch"];
        await context.Response.WriteAsync($"Branch used = {branchVer}");
    });
}

A tabela a seguir mostra as solicitações e respostas de http://localhost:1234 usando o código anterior:

Pedido Resposta
localhost:1234 Hello from non-Map delegate.
localhost:1234/?branch=main Branch used = main

UseWhen também divide o fluxo de solicitações com base no resultado do predicado dado. Ao contrário do MapWhen, essa ramificação é unida novamente ao pipeline principal se não contiver um middleware de terminal:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
    appBuilder => HandleBranchAndRejoin(appBuilder));

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

void HandleBranchAndRejoin(IApplicationBuilder app)
{
    var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>(); 

    app.Use(async (context, next) =>
    {
        var branchVer = context.Request.Query["branch"];
        logger.LogInformation("Branch used = {branchVer}", branchVer);

        // Do work that doesn't write to the Response.
        await next();
        // Do other work that doesn't write to the Response.
    });
}

No exemplo anterior, uma resposta de Hello from non-Map delegate. é escrita para todas as solicitações. Se a solicitação incluir uma variável de cadeia de caracteres de consulta branch, o seu valor será registado antes que o pipeline principal seja reintegrado.

Middleware integrado

ASP.NET Core é fornecido com os seguintes componentes de middleware. A coluna Order fornece notas sobre o posicionamento do middleware no pipeline de processamento de solicitações e em que condições o middleware pode encerrar o processamento de solicitações. Quando um middleware interrompe o pipeline de processamento de solicitações e impede que qualquer outro middleware subsequente processe uma solicitação, é chamado de middleware terminal. Para mais informações sobre curto-circuitagem, consulte a seção Criar um pipeline de middleware com WebApplication.

Middleware Descrição Encomenda
Autenticação Fornece suporte à autenticação. Antes HttpContext.User é necessário. Terminal para retornos de chamada OAuth.
Autorização Fornece suporte de autorização. Imediatamente após o middleware de autenticação.
Política Cookie Rastreia o consentimento dos utilizadores para armazenar informações pessoais e impõe padrões mínimos para campos cookie, como secure e SameSite. Antes do middleware que emite cookies. Exemplos: Autenticação, Sessão, MVC (TempData).
CORS Configura o compartilhamento de recursos entre origens. Antes de componentes que usam CORS. Atualmente, UseCors deve ir antes de UseResponseCaching devido a este bug .
Página de Exceção do Desenvolvedor Gera uma página com informações de erro que se destina a ser usada somente no ambiente de desenvolvimento. Antes de componentes que originam erros. Os modelos de projeto registram automaticamente esse middleware como o primeiro middleware no pipeline quando o ambiente é Desenvolvimento.
Diagnósticos Vários middlewares separados que fornecem uma página de exceção do desenvolvedor, tratamento de exceções, páginas de código de status e a página da Web padrão para novos aplicativos. Antes de componentes que geram erros. Terminal para gestão de exceções ou para servir a página web padrão para novas aplicações.
Cabeçalhos encaminhados Encaminha cabeçalhos com proxy para a solicitação atual. Antes dos componentes que consomem os campos atualizados. Exemplos: esquema, host, IP do cliente, método.
Verificação de Saúde Verifica a integridade de um aplicativo ASP.NET Core e suas dependências, como verificar a disponibilidade do banco de dados. Terminal se uma solicitação corresponder a um ponto de extremidade de verificação de integridade.
Propagação de Cabeçalho Propaga cabeçalhos HTTP da solicitação de entrada para as solicitações de cliente HTTP de saída.
Registo HTTP Registra solicitações e respostas HTTP. No início do pipeline de middleware.
Substituição de Método HTTP Permite que uma solicitação POST de entrada substitua o método. Antes de componentes que consomem o método atualizado.
Redirecionamento HTTPS Redirecionar todas as solicitações HTTP para HTTPS. Antes dos componentes que consomem a URL.
Segurança de Transporte Rígida HTTP (HSTS) Middleware de aprimoramento de segurança que adiciona um cabeçalho de resposta especial. Antes das respostas serem enviadas e depois dos componentes que modificam as solicitações. Exemplos: cabeçalhos encaminhados, reescrita de URL.
MVC Processa solicitações com MVC/Razor Pages. Terminal se um pedido corresponder a uma rota.
OWIN Interoperabilidade com aplicativos, servidores e middleware baseados em OWIN. Terminal se o OWIN Middleware processar totalmente a solicitação.
cache de saída Fornece suporte para respostas de cache com base na configuração. Antes de componentes que exigem cache. UseRouting deve vir antes UseOutputCaching. UseCORS deve vir antes UseOutputCaching.
Cache de Resposta Fornece suporte para respostas em cache. Isso requer a participação do cliente para trabalhar. Use o cache de saída para controle completo do servidor. Antes de componentes que requerem cache. UseCORS deve vir antes UseResponseCaching. Normalmente, não é benéfico para aplicativos de interface do usuário, como Razor Pages, porque os navegadores geralmente definem cabeçalhos de solicitação que impedem o armazenamento em cache. A cache de saída beneficia aplicações de interface de utilizador.
Solicitação de descompressão Fornece suporte para solicitações de descompactação. Antes dos componentes que leem o corpo da solicitação.
Compressão de Resposta Fornece suporte para compressão de respostas. Antes de componentes que requerem compressão.
Solicitar localização Fornece suporte à localização. Antes da localização de componentes sensíveis. Deve aparecer após o Routing Middleware ao usar RouteDataRequestCultureProvider.
Tempo limite de solicitação Fornece suporte para configurar tempos limite de solicitação, globais e por ponto de extremidade. UseRequestTimeouts deve vir depois de UseExceptionHandler, UseDeveloperExceptionPagee UseRouting.
Roteamento de Endpoint Define e restringe rotas de solicitação. Terminal para combinação de rotas.
SPA Trata todas as solicitações deste ponto na cadeia de middleware, retornando a página padrão para a Aplicação de Página Única (SPA) No final da cadeia, de modo que outro middleware, como para servir ficheiros estáticos e ações MVC, tenha precedência.
Sessão Fornece suporte para gerenciar sessões de usuário. Antes de componentes que requerem Sessão.
Arquivos Estáticos Fornece suporte para servir arquivos estáticos e navegação em diretórios. Terminal se uma solicitação corresponder a um arquivo.
Reescrita de URL Fornece suporte para reescrever URLs e redirecionar solicitações. Antes dos componentes que consomem a URL.
W3CLogging Gera logs de acesso ao servidor no W3C Extended Log File Format. No início do pipeline de middleware.
WebSockets Habilita o protocolo WebSockets. Antes dos componentes necessários para processar pedidos WebSocket.

Recursos adicionais

Por Rick Anderson e Steve Smith

Middleware é um software montado em um pipeline de aplicativos para lidar com solicitações e respostas. Cada componente:

  • Escolhe se deseja passar a solicitação para o próximo componente no pipeline.
  • Pode executar tarefas antes e depois do próximo componente na pipeline.

Os delegados de solicitação são usados para criar o pipeline de solicitação. Os delegados de solicitação lidam com cada solicitação HTTP.

Os delegados de solicitação são configurados usando os métodos de extensão Run, Mape Use. Um delegado de solicitação individual pode ser especificado em linha como um método anônimo (chamado middleware in-line) ou pode ser definido em uma classe reutilizável. Essas classes reutilizáveis e métodos anônimos em linha são middleware, também chamados de componentes de middleware . Cada componente de middleware no pipeline de solicitação é responsável por invocar o próximo componente no pipeline ou curto-circuitar o pipeline. Quando um middleware entra em curto-circuito, ele é chamado de de middleware de terminal porque impede que mais middleware processe a solicitação.

Migrar manipuladores e módulos HTTP para ASP.NET middleware Core explica a diferença entre pipelines de solicitação no ASP.NET Core e no ASP.NET 4.x e fornece exemplos adicionais de middleware.

A função do middleware por tipo de aplicativo

Razor Pages, MVC, Blazor Servere o projeto do lado do servidor de uma solução de Blazor WebAssembly hospedada processam solicitações de navegador no servidor com middleware. As orientações neste artigo aplicam-se a estes tipos de aplicações.

Os aplicativos Blazor WebAssembly autônomos são executados inteiramente no cliente e não processam solicitações com um pipeline de middleware. As orientações neste artigo não se aplicam a aplicativos Blazor WebAssembly autônomos.

Análise de código de middleware

ASP.NET Core inclui muitos analisadores de plataforma de compilador que inspecionam o código do aplicativo quanto à qualidade. Para obter mais informações, consulte Análise de código em aplicativos ASP.NET Core

Crie uma cadeia de middleware com WebApplication

O pipeline de solicitação ASP.NET Core consiste em uma sequência de delegados de solicitação, chamados um após o outro. O diagrama a seguir demonstra o conceito. O fio da execução segue as setas pretas.

Padrão de processamento de solicitação mostrando uma solicitação chegando, processando por meio de três middlewares e a resposta saindo do aplicativo. Cada middleware executa sua lógica e entrega a solicitação para o próximo middleware na instrução next(). Depois que o terceiro middleware processa a solicitação, a solicitação passa de volta pelos dois middlewares anteriores em ordem inversa para processamento adicional após suas instruções next() antes de sair do aplicativo como resposta ao cliente.

Cada delegado pode executar operações antes e depois do próximo delegado. Os delegados de tratamento de exceções devem ser invocados no início do pipeline, para que possam intercetar exceções que ocorram em fases posteriores do pipeline.

O aplicativo ASP.NET Core mais simples possível configura um único delegado de solicitação que lida com todas as solicitações. Este caso não inclui um pipeline de solicitação real. Em vez disso, uma única função anônima é chamada em resposta a cada solicitação HTTP.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello world!");
});

app.Run();

Encadeie vários delegados de solicitação com Use. O parâmetro next representa o próximo delegado no pipeline. Você pode curto-circuitar o pipeline não chamando o parâmetro next. Normalmente, pode realizar ações tanto antes como depois do delegado next, como demonstra o exemplo a seguir:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

Quando um delegado não passa uma solicitação para o próximo delegado, ele é chamado de curto-circuito pipeline de solicitação. O curto-circuito é muitas vezes desejável porque evita trabalho desnecessário. Por exemplo, de middleware de arquivo estático pode atuar como um de middleware de terminal de processando uma solicitação para um arquivo estático e curto-circuitando a do pipeline. O middleware adicionado ao pipeline antes do middleware que encerra o processamento adicional ainda processa o código após suas instruções next.Invoke. No entanto, consulte o seguinte aviso sobre tentar escrever uma resposta que já foi enviada.

Advertência

Não ligue para next.Invoke depois que a resposta for enviada ao cliente. Alterações no HttpResponse após o início da resposta geram uma exceção. Por exemplo, definir cabeçalhos e um código de status lançam uma exceção. Escrevendo para o corpo de resposta depois de ligar para next:

  • Pode causar uma violação de protocolo. Por exemplo, escrever mais do que o indicado Content-Length.
  • Pode corromper o formato do corpo. Por exemplo, escrever um rodapé HTML em um arquivo CSS.

HasStarted é uma dica útil para indicar se os cabeçalhos já foram enviados ou se o corpo já foi escrito.

Run delegados não recebem o parâmetro next. O primeiro Run delegado é sempre terminal e encerra o pipeline. Run é uma convenção. Alguns componentes de middleware podem expor Run[Middleware] métodos que são executados no final do pipeline.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

Se gostaria de ver os comentários de código traduzidos para outros idiomas além do inglês, informe-nos nesta questão de discussão no GitHub .

No exemplo anterior, o delegado Run escreve "Hello from 2nd delegate." na resposta e, em seguida, termina o pipeline. Se outro delegado Use ou Run for adicionado após o delegado Run, ele não será chamado.

Prefira o aplicativo. Usar sobrecarga que requer passar o contexto para o próximo

A não alocação aplicativo. Use método de extensão:

  • É necessário passar o contexto para next.
  • Salva duas alocações internas por solicitação que são necessárias ao usar a outra sobrecarga.

Para obter mais informações, consulte este problema do GitHub.

Ordem de middleware

O diagrama a seguir mostra o pipeline completo de processamento de solicitações para ASP.NET aplicativos Core MVC e Razor Pages. Você pode ver como, numa aplicação típica, os middlewares existentes são ordenados e onde são adicionados os middlewares personalizados. Você tem controle total sobre como reordenar middlewares existentes ou injetar novos middlewares personalizados conforme necessário para seus cenários.

Pipeline de middleware do ASP.NET Core

O middleware Endpoint no diagrama anterior executa o pipeline de filtro para o tipo de aplicativo correspondente — MVC ou Razor Pages.

O middleware de Roteamento é mostrado no diagrama anterior após os Arquivos Estáticos . Esta é a ordem que os modelos de projeto implementam chamando explicitamente aplicativo. UseRouting. Se você não chamar app.UseRouting, o middleware Roteamento é executado no início do pipeline por padrão. Para obter mais informações, consulte Roteamento.

ASP.NET Core pipeline de filtragem

A ordem em que os componentes de middleware são adicionados no arquivo de Program.cs define a ordem em que os componentes de middleware são invocados nas solicitações e a ordem inversa para a resposta. A ordem é crítica para segurança, desempenho e funcionalidade.

O código realçado a seguir no Program.cs adiciona componentes de middleware relacionados à segurança na ordem recomendada típica:

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMiddleware.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
    ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();

app.UseRouting();
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

No código anterior:

  • Middleware que não é adicionado ao criar um novo aplicativo Web com contas de usuários individuais é comentado.
  • Nem todo middleware aparece nessa ordem exata, mas muitos aparecem. Por exemplo:
    • UseCors, UseAuthenticatione UseAuthorization devem aparecer na ordem mostrada.
    • UseCors atualmente deve ser colocado antes de UseResponseCaching. Este requisito é explicado na issue do GitHub dotnet/aspnetcore #23218.
    • UseRequestLocalization deve aparecer antes de qualquer middleware que possa verificar a cultura de solicitação, por exemplo, app.UseStaticFiles().
    • UseRateLimiter deve ser chamado após UseRouting quando APIs específicas de limite de taxa são usadas. Por exemplo, se o atributo [EnableRateLimiting] for usado, UseRateLimiter deverá ser chamado após UseRouting. Ao chamar apenas limitadores globais, UseRateLimiter pode ser chamado antes de UseRouting.

Em alguns cenários, o middleware tem ordenamentos diferentes. Por exemplo, a ordem de cache e compactação é específica do cenário e há várias ordens válidas. Por exemplo:

app.UseResponseCaching();
app.UseResponseCompression();

Com o código anterior, o uso da CPU pode ser reduzido armazenando em cache a resposta compactada, mas você pode acabar armazenando em cache várias representações de um recurso usando diferentes algoritmos de compactação, como Gzip ou Brotli.

A seguinte ordenação combina arquivos estáticos para permitir o armazenamento em cache de arquivos estáticos compactados:

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

O código Program.cs a seguir adiciona componentes de middleware para cenários comuns de aplicativos:

  1. Tratamento de exceções/erros
    • Quando o aplicativo é executado no ambiente de desenvolvimento:
      • O Middleware da Página de Exceção do Desenvolvedor (UseDeveloperExceptionPage) relata erros de tempo de execução do aplicativo.
      • A página de erro do banco de dados no middleware (UseDatabaseErrorPage) relata erros durante a execução do banco de dados.
    • Quando o aplicativo é executado no ambiente de produção:
      • O Exception Handler Middleware (UseExceptionHandler) captura exceções lançadas nos seguintes middlewares.
      • HTTP Strict Transport Security Protocol (HSTS) Middleware (UseHsts) adiciona o cabeçalho Strict-Transport-Security.
  2. HTTPS Redirection Middleware (UseHttpsRedirection) redireciona solicitações HTTP para HTTPS.
  3. Static File Middleware (UseStaticFiles) retorna ficheiros estáticos e interrompe o processamento de solicitações adicionais.
  4. Cookie Policy Middleware (UseCookiePolicy) está em conformidade com a aplicação com os regulamentos do Regulamento Geral sobre a Proteção de Dados (RGPD) da UE.
  5. Middleware de roteamento (UseRouting) para rotear solicitações.
  6. O middleware de autenticação (UseAuthentication) tenta autenticar o usuário antes que ele tenha acesso a recursos seguros.
  7. O middleware de autorização (UseAuthorization) autoriza um usuário a acessar recursos seguros.
  8. O middleware de sessão (UseSession) estabelece e mantém o estado da sessão. Se a aplicação utilizar o estado de sessão, chame o Middleware de Sessão após o Middleware de Política Cookie e antes do Middleware MVC.
  9. Middleware de Roteamento de Ponto Final (UseEndpoints com MapRazorPages) para adicionar endpoints das Páginas Razor ao pipeline de solicitação.
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseDatabaseErrorPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();

No código de exemplo anterior, cada método de extensão de middleware é exposto em WebApplicationBuilder através do namespace Microsoft.AspNetCore.Builder.

UseExceptionHandler é o primeiro componente de middleware adicionado ao pipeline. Portanto, o Exception Handler Middleware captura quaisquer exceções que ocorram em chamadas posteriores.

O Middleware de Arquivo Estático é invocado no início do pipeline para que possa processar as solicitações e interromper o processamento sem passar pelos componentes restantes. O middleware de arquivo estático não fornece nenhuma verificação de autorização. Todos os arquivos servidos pelo Static File Middleware, incluindo aqueles sob wwwroot, estão disponíveis publicamente. Para obter uma abordagem para proteger arquivos estáticos, consulte Arquivos estáticos no ASP.NET Core.

Se a solicitação não for tratada pelo Middleware de Arquivo Estático, ela será passada para o Middleware de Autenticação (UseAuthentication), que executa a autenticação. A autenticação não provoca curto-circuito em solicitações não autenticadas. Embora o Middleware de Autenticação autentique os pedidos, a autorização (e a rejeição) ocorre somente depois de o MVC selecionar uma página de Razor ou um controlador e uma ação MVC determinados.

O exemplo a seguir demonstra uma ordem de middleware em que as solicitações de arquivos estáticos são tratadas pelo Static File Middleware antes do Response Compression Middleware. Os arquivos estáticos não são compactados com essa ordem de middleware. As respostas do Razor Pages podem ser compactadas.

// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();

app.UseRouting();

app.UseResponseCompression();

app.MapRazorPages();

Para obter informações sobre aplicativos de página única, consulte os guias para os modelos de projeto React e Angular.

Ordem de UseCors e UseStaticFiles

A ordem para chamar UseCors e UseStaticFiles depende do aplicativo. Para mais informações, consulte a ordem UseCors e UseStaticFiles

Ordem do Middleware de Encaminhamento de Cabeçalhos

O middleware de cabeçalhos encaminhados deve ser executado antes de outros middleware. Essa ordenação garante que o middleware que depende das informações de cabeçalhos encaminhados possa consumir os valores de cabeçalho para processamento. Para executar o middleware de cabeçalhos encaminhados após o middleware de diagnóstico e tratamento de erros, consulte ordem de middleware de cabeçalhos encaminhados.

Ramificar o pipeline de middleware

Extensões Map são utilizadas como convenção para ramificar o pipeline. Map ramifica o pipeline de solicitação com base nas correspondências do caminho de solicitação fornecido. Se o caminho da solicitação começar com o caminho fornecido, a ramificação será executada.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1", HandleMapTest1);

app.Map("/map2", HandleMapTest2);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMapTest1(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

static void HandleMapTest2(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 2");
    });
}

A tabela a seguir mostra as solicitações e respostas de http://localhost:1234 usando o código anterior.

Solicitar Resposta
localhost:1234 Olá do delegado que não pertence ao Mapa.
localhost:1234/mapa1 Teste de Mapa 1
localhost:1234/map2 Teste de Mapa 2
localhost:1234/map3 Olá do delegado de fora do Mapa.

Quando Map é usado, os segmentos de caminho correspondentes são removidos do HttpRequest.Path e anexados ao HttpRequest.PathBase para cada solicitação.

Map suporta aninhamento, por exemplo:

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

Map também pode corresponder a vários segmentos ao mesmo tempo:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1/seg1", HandleMultiSeg);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMultiSeg(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

MapWhen ramifica o pipeline de solicitação com base no resultado do predicado dado. Qualquer predicado do tipo Func<HttpContext, bool> pode ser usado para mapear solicitações para uma nova ramificação do pipeline. No exemplo a seguir, um predicado é usado para detetar a presença de uma variável de cadeia de caracteres de consulta branch:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        var branchVer = context.Request.Query["branch"];
        await context.Response.WriteAsync($"Branch used = {branchVer}");
    });
}

A tabela a seguir mostra as solicitações e respostas de http://localhost:1234 usando o código anterior:

Pedido Resposta
localhost:1234 Hello from non-Map delegate.
localhost:1234/?branch=main Branch used = main

UseWhen também ramifica o pipeline de solicitação com base no resultado do predicado dado. Ao contrário de MapWhen, este ramo é ligado novamente ao pipeline principal se não causar curto-circuito nem contiver um middleware terminal.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
    appBuilder => HandleBranchAndRejoin(appBuilder));

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

void HandleBranchAndRejoin(IApplicationBuilder app)
{
    var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>(); 

    app.Use(async (context, next) =>
    {
        var branchVer = context.Request.Query["branch"];
        logger.LogInformation("Branch used = {branchVer}", branchVer);

        // Do work that doesn't write to the Response.
        await next();
        // Do other work that doesn't write to the Response.
    });
}

No exemplo anterior, uma resposta de Hello from non-Map delegate. é escrita para todas as solicitações. Se a solicitação incluir um parâmetro de consulta branch, o seu valor será registado antes que o pipeline principal seja retomado.

Middleware integrado

ASP.NET Core é fornecido com os seguintes componentes de middleware. A coluna Order fornece notas sobre o posicionamento do middleware no pipeline de processamento de solicitações e em que condições o middleware pode encerrar o processamento de solicitações. Quando um middleware curto-circuita o pipeline de processamento de solicitações e impede que mais middleware downstream processe uma solicitação, ele é chamado de middleware de terminal . Para obter mais informações sobre curto-circuito, consulte a seção Criar um pipeline de middleware com WebApplication.

Middleware Descrição Encomenda
Autenticação Fornece suporte à autenticação. Antes HttpContext.User é necessário. Terminal para retornos de chamada OAuth.
Autorização Fornece suporte de autorização. Imediatamente após o middleware de autenticação.
Política Cookie Rastreia o consentimento dos utilizadores para o armazenamento de informações pessoais e impõe padrões mínimos para campos cookie, como secure e SameSite. Antes do middleware que emite cookies. Exemplos: Autenticação, Sessão, MVC (TempData).
CORS Configura o compartilhamento de recursos entre origens. Antes de componentes que usam CORS. UseCors atualmente deve ir antes de UseResponseCaching devido a este bug .
PáginaDeExceçãoDeDesenvolvedor Gera uma página com informações de erro que se destina a ser usada somente no ambiente de desenvolvimento. Antes de componentes que geram erros. Os modelos de projeto registram automaticamente esse middleware como o primeiro middleware no pipeline quando o ambiente é Desenvolvimento.
Diagnósticos Vários middlewares separados que fornecem uma página de exceção do desenvolvedor, tratamento de exceções, páginas de código de status e a página da Web padrão para novos aplicativos. Antes de componentes que geram erros. Terminal para exceções ou servindo a página da Web padrão para novos aplicativos.
Cabeçalhos encaminhados Redireciona cabeçalhos proxy para a solicitação atual. Antes de os componentes consumirem os campos atualizados. Exemplos: esquema, host, IP do cliente, método.
verificação de integridade Verifica a integridade de um aplicativo ASP.NET Core e suas dependências, como verificar a disponibilidade do banco de dados. Terminal se uma solicitação corresponder a um endpoint de verificação de integridade.
Propagação de Cabeçalho Propaga cabeçalhos HTTP da solicitação de entrada para as solicitações de cliente HTTP de saída.
Registo HTTP Registra solicitações e respostas HTTP. No início do pipeline de middleware.
Substituição de Método HTTP Permite que uma solicitação POST de entrada substitua o método. Antes de componentes que consomem o método atualizado.
Redirecionamento HTTPS Redirecionar todas as solicitações HTTP para HTTPS. Antes dos componentes que utilizam a URL.
Segurança de Transporte Estrita HTTP (HSTS) Middleware de aprimoramento de segurança que adiciona um cabeçalho de resposta especial. Antes de as respostas serem enviadas e após os componentes que modificam as solicitações. Exemplos: cabeçalhos encaminhados, reescrita de URL.
MVC Processa solicitações com MVC/Razor Pages. Terminal caso uma requisição corresponda a uma rota.
OWIN Interoperabilidade com aplicativos, servidores e middleware baseados em OWIN. Terminal se o OWIN Middleware processar totalmente a solicitação.
cache de saída Fornece suporte para respostas de cache com base na configuração. Antes de componentes que necessitam de cache. UseRouting deve vir antes UseOutputCaching. UseCORS deve vir antes UseOutputCaching.
Cache de Resposta Fornece suporte para respostas em cache. Isso requer a participação do cliente para trabalhar. Use o cache de saída para controle completo do servidor. Antes de componentes que exigem cache. UseCORS deve vir antes UseResponseCaching. Normalmente, não é benéfico para aplicativos de interface do usuário, como Razor Pages, porque os navegadores geralmente definem cabeçalhos de solicitação que impedem o armazenamento em cache. O cache de saída beneficia os aplicativos da interface do usuário.
Pedido de Descompressão Fornece suporte para solicitações de descompactação. Antes dos componentes que leem o corpo da solicitação.
Compressão de Resposta Fornece suporte para compressão de respostas. Antes de componentes que requerem compressão.
Solicitar localização Fornece suporte à localização. Antes da localização de componentes sensíveis. Deve aparecer após o Routing Middleware ao usar RouteDataRequestCultureProvider.
Roteamento de Endpoint Define e restringe rotas de solicitação. Terminal para emparelhamento de rotas.
SPA Trata de todas as solicitações a partir deste ponto na cadeia de middleware, retornando a página padrão para a Aplicação de Página Única (SPA) No final da cadeia, para que outro middleware para servir arquivos estáticos, ações MVC, etc., possa ter prioridade.
Sessão Fornece suporte para gerenciar sessões de usuário. Antes de componentes que requerem Sessão.
Arquivos Estáticos Fornece suporte para servir arquivos estáticos e navegação em diretórios. Terminal se uma solicitação corresponder a um arquivo.
Reescrita de URL Fornece suporte para reescrever URLs e redirecionar solicitações. Antes dos componentes que consomem a URL.
W3CLogging Gera logs de acesso ao servidor no W3C Extended Log File Format. No início do pipeline de middleware.
WebSockets Habilita o protocolo WebSockets. Antes dos componentes necessários para aceitar solicitações WebSocket.

Recursos adicionais

Por Rick Anderson e Steve Smith

Middleware é um software montado em um pipeline de aplicativos para lidar com solicitações e respostas. Cada componente:

  • Escolhe se deseja passar a solicitação para o próximo componente no pipeline.
  • Pode executar trabalho antes e depois do próximo componente no pipeline.

Os delegados de solicitação são usados para criar o pipeline de solicitação. Os delegados de solicitação lidam com cada solicitação HTTP.

Os delegados de solicitação são configurados usando métodos de extensão Run, Mape Use. Um delegado de solicitação individual pode ser especificado em linha como um método anônimo (chamado middleware in-line) ou pode ser definido em uma classe reutilizável. Essas classes reutilizáveis e métodos anônimos em linha são middleware, também chamados de componentes de middleware . Cada componente de middleware no pipeline de solicitação é responsável por invocar o próximo componente no pipeline ou curto-circuitar o pipeline. Quando um middleware faz curto-circuito, é chamado de middleware terminal porque impede que mais middleware processe a solicitação.

Migrar manipuladores e módulos HTTP para middleware do ASP.NET Core explica a diferença entre pipelines de pedidos no ASP.NET Core e no ASP.NET 4.x e fornece exemplos adicionais de middleware.

Análise de código de middleware

ASP.NET Core inclui muitos analisadores de plataforma de compilador que inspecionam o código do aplicativo quanto à qualidade. Para obter mais informações, consulte Análise de código em aplicativos ASP.NET Core

Crie uma pipeline de middleware com WebApplication

O pipeline de solicitação ASP.NET Core consiste em uma sequência de delegados de solicitação, chamados um após o outro. O diagrama a seguir demonstra o conceito. O fio da execução segue as setas pretas.

Padrão de processamento de solicitação mostrando uma solicitação chegando, processando por meio de três middlewares e a resposta saindo do aplicativo. Cada middleware executa sua lógica e entrega a solicitação para o próximo middleware na instrução next(). Depois que o terceiro middleware processa a solicitação, a solicitação passa de volta pelos dois middlewares anteriores em ordem inversa para processamento adicional após suas instruções next() antes de sair do aplicativo como resposta ao cliente.

Cada delegado pode executar operações antes e depois do próximo delegado. Os delegados de tratamento de exceções devem ser chamados no início do pipeline, para que possam capturar exceções que ocorrem em estágios posteriores do pipeline.

O aplicativo ASP.NET Core mais simples possível configura um único delegado de solicitação que lida com todas as solicitações. Este caso não inclui um pipeline de solicitação real. Em vez disso, uma única função anônima é chamada em resposta a cada solicitação HTTP.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello world!");
});

app.Run();

Encadeie vários delegados de solicitação junto com Use. O parâmetro next representa o próximo delegado no pipeline. Você pode curto-circuitar o pipeline não chamando o parâmetro next. Normalmente, você pode executar ações antes e depois do next delegado, como demonstra o exemplo a seguir:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

Quando um delegado não passa uma solicitação para o próximo delegado, ele é chamado de curto-circuito pipeline de solicitação. O curto-circuito é frequentemente desejável porque evita trabalho desnecessário. Por exemplo, de middleware de arquivo estático pode atuar como um de middleware de terminal de processando uma solicitação para um arquivo estático e curto-circuitando a do pipeline. O middleware adicionado ao pipeline antes do middleware que encerra o processamento adicional ainda processa o código após suas instruções next.Invoke. No entanto, consulte o seguinte aviso sobre tentar escrever em uma resposta que já foi enviada.

Advertência

Não ligue para next.Invoke depois que a resposta for enviada ao cliente. Alterações no HttpResponse após o início da resposta geram uma exceção. Por exemplo, definir cabeçalhos e um código de status lança uma exceção. Escrevendo para o corpo de resposta depois de ligar para next:

  • Pode causar uma violação de protocolo. Por exemplo, escrever mais do que o que foi indicado Content-Length.
  • Pode corromper o formato do corpo. Por exemplo, escrever um rodapé HTML em um arquivo CSS.

HasStarted é uma sugestão útil para indicar se os cabeçalhos foram enviados ou se o corpo foi escrito.

Run delegados não recebem o parâmetro next. O primeiro Run delegate é sempre terminal e encerra o pipeline. Run é uma convenção. Alguns componentes de middleware podem expor métodos Run[Middleware] que são executados no final do pipeline:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

Se você gostaria de ver os comentários de código traduzidos para outros idiomas além do inglês, informe-nos em este problema de discussão do GitHub.

No exemplo anterior, o delegado Run grava "Hello from 2nd delegate." na resposta e depois encerra o pipeline. Se um delegado Use ou Run for adicionado após o delegado Run, esse delegado não será chamado.

Prefira o aplicativo. Usar sobrecarga que requer passar o contexto para o próximo

A não alocação aplicativo. Use método de extensão:

  • Requer passar o contexto para next.
  • Evita duas alocações internas por cada pedido que são necessárias ao utilizar a outra sobrecarga.

Para obter mais informações, consulte este problema do GitHub.

Ordem de middleware

O diagrama a seguir mostra o pipeline completo de processamento de solicitações para ASP.NET aplicativos Core MVC e Razor Pages. Você pode ver como, numa aplicação típica, os middlewares existentes são ordenados e onde os middlewares personalizados são adicionados. Você tem controle total sobre como reordenar middlewares existentes ou injetar novos middlewares personalizados conforme necessário para seus cenários.

Pipeline de middleware do ASP.NET Core

O middleware Endpoint no diagrama anterior executa o pipeline de filtro para o tipo de aplicativo correspondente — MVC ou Razor Pages.

O middleware Roteamento no diagrama anterior é mostrado após Arquivos Estáticos. Esta é a ordem que os modelos de projeto implementam chamando explicitamente app.UseRouting. Se você não chamar app.UseRouting, o middleware Roteamento é executado no início do pipeline por padrão. Para obter mais informações, consulte Enrutamento.

ASP.NET Core pipeline de filtros

A ordem em que os componentes de middleware são adicionados no arquivo de Program.cs define a ordem em que os componentes de middleware são invocados nas solicitações e a ordem inversa para a resposta. A ordem é crítica para segurança, desempenho e funcionalidade.

O código realçado a seguir no Program.cs adiciona componentes de middleware relacionados à segurança na ordem recomendada típica:

using IndividualAccountsExample.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();

app.UseRouting();
// app.UseRequestLocalization();
// app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapRazorPages();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

No código anterior:

  • Middleware que não é adicionado ao criar um novo aplicativo Web com contas de usuários individuais é comentado.
  • Nem todo middleware aparece nessa ordem exata, mas muitos aparecem. Por exemplo:
    • UseCors, UseAuthenticatione UseAuthorization devem aparecer na ordem mostrada.
    • UseCors atualmente deve comparecer antes de UseResponseCaching. Este requisito é explicado em problema do GitHub dotnet/aspnetcore #23218.
    • UseRequestLocalization deve aparecer antes de qualquer middleware que possa verificar a cultura de solicitação (por exemplo, app.UseMvcWithDefaultRoute()).

Em alguns cenários, a middleware tem uma ordem diferente. Por exemplo, a ordem de cache e compactação é específica do cenário e há várias ordens válidas. Por exemplo:

app.UseResponseCaching();
app.UseResponseCompression();

Com o código anterior, o uso da CPU pode ser reduzido armazenando em cache a resposta compactada, mas você pode acabar armazenando em cache várias representações de um recurso usando diferentes algoritmos de compactação, como Gzip ou Brotli.

A seguinte ordenação combina arquivos estáticos para permitir o armazenamento em cache de arquivos estáticos compactados:

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

O código Program.cs a seguir adiciona componentes de middleware para cenários comuns de aplicativos:

  1. Tratamento de exceções/erros
    • Quando o aplicativo é executado no ambiente de desenvolvimento:
      • O Middleware da Página de Exceção do Desenvolvedor (UseDeveloperExceptionPage) relata erros de execução da aplicação.
      • O middleware da página de erro do banco de dados (UseDatabaseErrorPage) reporta erros em tempo de execução do banco de dados.
    • Quando o aplicativo é executado no ambiente de produção:
      • O Exception Handler Middleware (UseExceptionHandler) captura exceções lançadas nos seguintes middlewares.
      • HTTP Strict Transport Security Protocol (HSTS) Middleware (UseHsts) adiciona o cabeçalho Strict-Transport-Security.
  2. HTTPS Redirection Middleware (UseHttpsRedirection) redireciona solicitações HTTP para HTTPS.
  3. Static File Middleware (UseStaticFiles) retorna ficheiros estáticos e interrompe o processamento adicional de solicitações.
  4. Cookie Policy Middleware (UseCookiePolicy) está em conformidade com a aplicação com os regulamentos do Regulamento Geral sobre a Proteção de Dados (RGPD) da UE.
  5. Middleware de roteamento (UseRouting) para rotear solicitações.
  6. O middleware de autenticação (UseAuthentication) tenta autenticar o usuário antes que ele tenha acesso a recursos seguros.
  7. O middleware de autorização (UseAuthorization) autoriza um usuário a acessar recursos seguros.
  8. O middleware de sessão (UseSession) estabelece e mantém o estado da sessão. Se a aplicação usar o estado da sessão, chame o Middleware de Sessão depois do Middleware de Política de Cookie e antes do Middleware MVC.
  9. Middleware de Endpoint Routing (UseEndpoints com MapRazorPages) para adicionar endpoints de Razor Pages ao pipeline de solicitação.
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseDatabaseErrorPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();

No código de exemplo anterior, cada método de extensão de middleware é exposto em WebApplicationBuilder através do namespace Microsoft.AspNetCore.Builder.

UseExceptionHandler é o primeiro componente de middleware adicionado ao pipeline. Portanto, o Exception Handler Middleware captura quaisquer exceções que ocorram em chamadas posteriores.

O Middleware de Arquivo Estático é chamado no início do pipeline para que possa lidar com solicitações e curto-circuito sem passar pelos componentes restantes. O middleware de arquivo estático não fornece nenhuma verificação de autorização. Todos os arquivos servidos pelo Static File Middleware, incluindo aqueles sob wwwroot, estão disponíveis publicamente. Para obter uma abordagem para proteger arquivos estáticos, consulte Arquivos estáticos no ASP.NET Core.

Se a solicitação não for tratada pelo Middleware de Arquivo Estático, ela será passada para o Middleware de Autenticação (UseAuthentication), que executa a autenticação. A autenticação não provoca curto-circuito em solicitações não autenticadas. Embora o Middleware de Autenticação autentique pedidos, a autorização (e a rejeição) ocorre apenas depois que o MVC seleciona uma página específica de Razor ou um controlador e ação específicos do MVC.

O exemplo a seguir demonstra uma ordem de middleware em que as solicitações de arquivos estáticos são tratadas pelo Static File Middleware antes do Response Compression Middleware. Os arquivos estáticos não são compactados com essa ordem de middleware. As respostas do Razor Pages podem ser compactadas.

// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();

app.UseRouting();

app.UseResponseCompression();

app.MapRazorPages();

Para obter informações sobre aplicativos de página única, consulte os guias para os modelos de projeto React e Angular.

A ordem de UseCors e UseStaticFiles

A ordem para chamar UseCors e UseStaticFiles depende do aplicativo. Para obter mais informações, consulte ordem UseCors e UseStaticFiles

Ordem de middleware de cabeçalhos encaminhados

O Middleware dos Cabeçalhos Encaminhados deve ser executado antes de outros middlewares. Essa ordenação garante que o middleware que depende das informações de cabeçalhos encaminhados possa consumir os valores de cabeçalho para processamento. Para executar o middleware de cabeçalhos encaminhados após o middleware de diagnóstico e tratamento de erros, consulte a ordem do middleware de cabeçalhos encaminhados .

Ramifique o pipeline de middleware

As extensões Map são utilizadas como uma convenção para ramificar o pipeline. Map segmenta o pipeline de solicitação com base nas correspondências do caminho de pedido especificado. Se o caminho da solicitação começar com o caminho fornecido, a ramificação será executada.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1", HandleMapTest1);

app.Map("/map2", HandleMapTest2);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMapTest1(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

static void HandleMapTest2(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 2");
    });
}

A tabela a seguir mostra as solicitações e respostas de http://localhost:1234 usando o código anterior.

Pedido Resposta
localhost:1234 Olá do delegado fora do Mapa.
localhost:1234/mapa1 Teste de Mapa 1
localhost:1234/map2 Teste de Mapa 2
localhost:1234/map3 Olá do delegado fora do Mapa.

Quando Map é usado, os segmentos de caminho correspondentes são removidos do HttpRequest.Path e anexados ao HttpRequest.PathBase para cada solicitação.

Map suporta aninhamento, por exemplo:

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

Map também pode corresponder a vários segmentos ao mesmo tempo:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1/seg1", HandleMultiSeg);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMultiSeg(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

MapWhen ramifica o pipeline de solicitação com base no resultado do predicado dado. Qualquer predicado do tipo Func<HttpContext, bool> pode ser usado para mapear solicitações para uma nova ramificação do pipeline. No exemplo a seguir, um predicado é usado para detetar a presença de uma variável de cadeia de caracteres de consulta branch:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        var branchVer = context.Request.Query["branch"];
        await context.Response.WriteAsync($"Branch used = {branchVer}");
    });
}

A tabela a seguir mostra as solicitações e respostas de http://localhost:1234 usando o código anterior:

Solicitar Resposta
localhost:1234 Hello from non-Map delegate.
localhost:1234/?branch=main Branch used = main

UseWhen também ramifica o pipeline de solicitação com base no resultado do predicado dado. Ao contrário do MapWhen, essa ramificação é unida novamente ao pipeline principal se não houver curto-circuito ou contiver um middleware de terminal:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
    appBuilder => HandleBranchAndRejoin(appBuilder));

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

void HandleBranchAndRejoin(IApplicationBuilder app)
{
    var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>(); 

    app.Use(async (context, next) =>
    {
        var branchVer = context.Request.Query["branch"];
        logger.LogInformation("Branch used = {branchVer}", branchVer);

        // Do work that doesn't write to the Response.
        await next();
        // Do other work that doesn't write to the Response.
    });
}

No exemplo anterior, uma resposta de Hello from non-Map delegate. é escrita para todas as solicitações. Se a solicitação incluir uma variável de cadeia de caracteres de consulta branch, o seu valor será registado antes de ser retornado ao fluxo principal.

Middleware integrado

ASP.NET Core é fornecido com os seguintes componentes de middleware. A coluna Order fornece notas sobre o posicionamento do middleware no pipeline de processamento de solicitações e em que condições o middleware pode encerrar o processamento de solicitações. Quando um middleware interrompe o pipeline de processamento de solicitações e impede que outros middlewares na sequência processem uma solicitação, é chamado de middleware terminal . Para obter mais informações sobre curto-circuitagem, consulte a seção Criar um pipeline de middleware com WebApplication.

Middleware Descrição Encomenda
Autenticação Fornece suporte à autenticação. Antes HttpContext.User é necessário. Terminal para chamadas de retorno OAuth.
Autorização Fornece suporte de autorização. Imediatamente após o middleware de autenticação.
Política Cookie Rastreia o consentimento dos utilizadores para armazenar informações pessoais e impõe normas mínimas para campos cookie, como secure e SameSite. Antes do middleware que emite cookies. Exemplos: Autenticação, Sessão, MVC (TempData).
CORS Configura o compartilhamento de recursos entre origens. Antes de componentes que usam CORS. UseCors atualmente deve ir antes de UseResponseCaching devido a este bug.
PáginaDeExceçãoDoDesenvolvedor DeveloperExceptionPage Gera uma página com informações de erro que se destina a ser usada somente no ambiente de desenvolvimento. Antes de componentes que geram erros. Os modelos de projeto registram automaticamente esse middleware como o primeiro middleware no pipeline quando o ambiente é Desenvolvimento.
Diagnóstico Vários middlewares separados que fornecem uma página de exceção do desenvolvedor, tratamento de exceções, páginas de código de status e a página da Web padrão para novos aplicativos. Antes dos componentes que geram erros. Terminal para gerir exceções e servir a página Web padrão para novas aplicações.
Cabeçalhos encaminhados Encaminha cabeçalhos com proxy para a solicitação atual. Antes dos componentes que consomem os campos atualizados. Exemplos: esquema, host, IP do cliente, método.
de verificação de saúde Verifica a integridade de um aplicativo ASP.NET Core e suas dependências, como verificar a disponibilidade do banco de dados. Terminal se uma solicitação corresponder a um ponto de extremidade de verificação de integridade.
Propagação de Cabeçalhos Propaga cabeçalhos HTTP da solicitação de entrada para as solicitações de cliente HTTP de saída.
Registo HTTP Registra solicitações e respostas HTTP. No início do pipeline de middleware.
Substituição de Método HTTP Permite que uma solicitação POST de entrada substitua o método. Antes dos componentes que utilizam o método atualizado.
Redirecionamento HTTPS Redirecionar todas as solicitações HTTP para HTTPS. Antes dos componentes que consomem a URL.
Segurança Rigorosa de Transporte HTTP (HSTS) Middleware de aprimoramento de segurança que adiciona um cabeçalho de resposta especial. Antes de as respostas serem enviadas e após os componentes que modificam as requisições. Exemplos: cabeçalhos encaminhados, reescrita de URL.
MVC Processa solicitações com MVC/Razor Pages. Terminal se um pedido corresponder a uma rota.
OWIN Interoperabilidade com aplicativos, servidores e middleware baseados em OWIN. Terminal caso o Middleware OWIN tenha processado totalmente a solicitação.
Solicitar descompressão Fornece suporte para solicitações de descompactação. Antes dos componentes responsáveis por ler o corpo da solicitação.
Cache de Resposta Fornece suporte para respostas em cache. Antes de componentes que exigem armazenamento em cache. UseCORS deve vir antes UseResponseCaching.
Compressão de Resposta Fornece suporte para compressão de respostas. Antes de componentes que requerem compressão.
Solicitar localização Fornece suporte à localização. Antes da localização de componentes sensíveis. Deve aparecer após o Routing Middleware ao usar RouteDataRequestCultureProvider.
de roteamento de pontos finais Define e restringe rotas de solicitação. Terminal para correspondência de rotas.
SPA Manipula todas as solicitações deste ponto na cadeia de middleware, retornando a página padrão para a Aplicação de Página Única (SPA) No final da cadeia, de modo que o outro middleware que serve ficheiros estáticos, ações MVC, etc., tenha precedência.
Sessão Fornece suporte para gerenciar sessões de usuário. Antes dos componentes que requerem sessão.
arquivos estáticos Fornece suporte para servir arquivos estáticos e navegação em diretórios. Terminal se uma solicitação corresponder a um arquivo.
Reescrita de URL Fornece suporte para reescrever URLs e redirecionar solicitações. Antes dos componentes que consomem a URL.
W3CLogging Gera logs de acesso ao servidor no W3C Extended Log File Format. No início do pipeline de middleware.
WebSockets Habilita o protocolo WebSockets. Antes dos componentes necessários para aceitar solicitações WebSocket.

Recursos adicionais

Por Rick Anderson e Steve Smith

Middleware é um software montado em um pipeline de aplicativos para lidar com solicitações e respostas. Cada componente:

  • Escolhe se deseja passar a solicitação para o próximo componente no pipeline.
  • Pode executar trabalho antes e depois do próximo componente na canalização.

Os delegados de solicitação são usados para criar o pipeline de pedidos. Os delegados de solicitação lidam com cada solicitação HTTP.

Os delegados de solicitação são configurados usando métodos de extensão Run, Mape Use. Um delegado de solicitação individual pode ser especificado em linha como um método anônimo (chamado middleware in-line) ou pode ser definido em uma classe reutilizável. Essas classes reutilizáveis e métodos anônimos em linha são middleware, também chamados de componentes de middleware . Cada componente de middleware no fluxo de solicitação é responsável por invocar o próximo componente no fluxo ou interromper o fluxo. Quando um middleware corta o circuito, é chamado de middleware terminal porque impede que outros middleware processem a solicitação.

Migrar manipuladores e módulos HTTP para Middleware do ASP.NET Core explica a diferença entre os pipelines de solicitação no ASP.NET Core e no ASP.NET 4.x, e fornece exemplos adicionais de middleware.

Criar um pipeline de middleware com IApplicationBuilder

O pipeline de solicitação ASP.NET Core consiste em uma sequência de delegados de solicitação, chamados um após o outro. O diagrama a seguir demonstra o conceito. O fio da execução segue as setas pretas.

Padrão de processamento de solicitação mostrando uma solicitação chegando, processando por meio de três middlewares e a resposta saindo do aplicativo. Cada middleware executa sua lógica e entrega a solicitação para o próximo middleware na instrução next(). Depois que o terceiro middleware processa a solicitação, a solicitação passa de volta pelos dois middlewares anteriores em ordem inversa para processamento adicional após suas instruções next() antes de sair do aplicativo como resposta ao cliente.

Cada delegado pode executar operações antes e depois do próximo delegado. Os delegados de tratamento de exceções devem ser chamados no início do pipeline, para que possam interceptar exceções que ocorrem em estágios posteriores do pipeline.

O aplicativo ASP.NET Core mais simples possível configura um único delegado de solicitação que lida com todas as solicitações. Este caso não inclui um pipeline de solicitação real. Em vez disso, uma única função anônima é chamada em resposta a cada solicitação HTTP.

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello, World!");
        });
    }
}

Encadeie vários delegados de solicitação junto com Use. O parâmetro next representa o próximo delegado no pipeline. Você pode curto-circuitar o pipeline não chamando o próximo parâmetro. Normalmente, você pode executar ações antes e depois do próximo delegado, como demonstra o exemplo a seguir:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        });
    }
}

Quando um delegado não passa uma solicitação para o próximo delegado, ele é chamado de curto-circuito pipeline de solicitação. O curto-circuito é muitas vezes desejável porque evita trabalho desnecessário. Por exemplo, o Middleware de Arquivo Estático pode atuar como um middleware terminal de , processando uma solicitação para um arquivo estático e interrompendo o fluxo do pipeline. O middleware adicionado ao pipeline antes do middleware que encerra o processamento adicional ainda processa o código após suas instruções next.Invoke. No entanto, consulte o seguinte aviso sobre tentar gravar numa resposta que já foi enviada.

Advertência

Não ligue para next.Invoke depois que a resposta for enviada ao cliente. Alterações no HttpResponse após o início da resposta geram uma exceção. Por exemplo, definir cabeçalhos e um código de estado lança uma exceção. Escrevendo para o corpo de resposta depois de ligar para next:

  • Pode causar uma violação de protocolo. Por exemplo, escrever mais do que o indicado Content-Length.
  • Pode corromper o formato do corpo do documento. Por exemplo, escrever um rodapé HTML em um arquivo CSS.

HasStarted é uma dica útil para indicar se os cabeçalhos foram enviados ou se o corpo foi escrito.

Run delegates não recebem o parâmetro next. O primeiro delegado Run é sempre terminal e encerra o pipeline. Run é uma convenção. Alguns componentes de middleware podem expor os Run[Middleware] métodos que são executados no final do pipeline.

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        });
    }
}

Caso gostaria de ver os comentários de código traduzidos para outros idiomas além do inglês, diz-nos neste tópico de discussão no GitHub.

No exemplo anterior, o delegado Run grava "Hello from 2nd delegate." na resposta e, em seguida, encerra o pipeline. Se outro Use ou Run delegado for adicionado após o Run delegado, ele não será chamado.

Ordem de middleware

O diagrama a seguir mostra o pipeline completo de processamento de solicitações para ASP.NET aplicativos Core MVC e Razor Pages. Pode ver como, num aplicativo típico, os middlewares existentes são ordenados e onde os middlewares personalizados são adicionados. Você tem controle total sobre como reordenar middlewares existentes ou injetar novos middlewares personalizados conforme necessário para seus cenários.

Pipeline de middleware do ASP.NET Core

O middleware Endpoint no diagrama anterior executa o pipeline de filtro para o tipo de aplicativo correspondente — MVC ou Razor Pages.

ASP.NET Pipeline de filtro principal

A ordem em que os componentes de middleware são adicionados no método Startup.Configure define a ordem na qual os componentes de middleware são invocados em solicitações e a ordem inversa para a resposta. A ordem é crítica para segurança, desempenho e funcionalidade.

O seguinte método Startup.Configure adiciona componentes de middleware relacionados à segurança na ordem recomendada típica:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    // app.UseCookiePolicy();

    app.UseRouting();
    // app.UseRequestLocalization();
    // app.UseCors();

    app.UseAuthentication();
    app.UseAuthorization();
    // app.UseSession();
    // app.UseResponseCompression();
    // app.UseResponseCaching();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

No código anterior:

  • Middleware que não é adicionado ao criar uma nova aplicação Web com contas de utilizadores individuais é desativado com comentário.
  • Nem todo middleware aparece nessa ordem exata, mas muitos aparecem. Por exemplo:
    • UseCors, UseAuthenticatione UseAuthorization devem aparecer na ordem mostrada.
    • UseCors atualmente deve aparecer antes de UseResponseCaching devido a este bug .
    • UseRequestLocalization deve aparecer antes de qualquer middleware que possa verificar a cultura de solicitação (por exemplo, app.UseMvcWithDefaultRoute()).

Em alguns cenários, o middleware tem uma ordem diferente. Por exemplo, a ordem de cache e compactação é específica do cenário, e há vários pedidos válidos. Por exemplo:

app.UseResponseCaching();
app.UseResponseCompression();

Com o código anterior, a CPU poderia ser salva armazenando em cache a resposta compactada, mas você pode acabar armazenando em cache várias representações de um recurso usando diferentes algoritmos de compactação, como Gzip ou Brotli.

A seguinte ordenação combina arquivos estáticos para permitir o armazenamento em cache de arquivos estáticos compactados:

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

O método Startup.Configure a seguir adiciona componentes de middleware para cenários comuns de aplicativos:

  1. Tratamento de exceções/erros
    • Quando o aplicativo é executado no ambiente de desenvolvimento:
      • O Middleware da Página de Exceção do Desenvolvedor (UseDeveloperExceptionPage) reporta erros de tempo de execução da aplicação.
      • Página de Erro de Banco de Dados O Middleware relata erros de tempo de execução do banco de dados.
    • Quando o aplicativo é executado no ambiente de produção:
      • O Exception Handler Middleware (UseExceptionHandler) captura exceções lançadas nos seguintes middlewares.
      • HTTP Strict Transport Security Protocol (HSTS) Middleware (UseHsts) adiciona o cabeçalho Strict-Transport-Security.
  2. HTTPS Redirection Middleware (UseHttpsRedirection) redireciona solicitações HTTP para HTTPS.
  3. Static File Middleware (UseStaticFiles) retorna ficheiros estáticos e interrompe o processamento adicional das solicitações.
  4. Cookie Policy Middleware (UseCookiePolicy) está em conformidade com a aplicação com os regulamentos do Regulamento Geral sobre a Proteção de Dados (RGPD) da UE.
  5. Middleware de roteamento (UseRouting) para rotear solicitações.
  6. O middleware de autenticação (UseAuthentication) tenta autenticar o usuário antes que ele tenha acesso a recursos seguros.
  7. O middleware de autorização (UseAuthorization) autoriza um usuário a acessar recursos seguros.
  8. O middleware de sessão (UseSession) estabelece e mantém o estado da sessão. Se a aplicação utilizar o estado de sessão, invoque o Middleware de Sessão depois do Middleware de Política de Cookie e antes do Middleware MVC.
  9. Middleware de Roteamento de Ponto Final (UseEndpoints com MapRazorPages) para adicionar os endpoints de Razor Pages ao pipeline de pedidos.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseSession();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

No código de exemplo anterior, cada método de extensão de middleware é exposto em IApplicationBuilder através do namespace Microsoft.AspNetCore.Builder.

UseExceptionHandler é o primeiro componente de middleware adicionado ao pipeline. Portanto, o Exception Handler Middleware captura quaisquer exceções que ocorram em chamadas posteriores.

O Middleware de Arquivo Estático é chamado no início do pipeline para que possa lidar com solicitações e curto-circuito sem passar pelos componentes restantes. O middleware de arquivo estático não fornece nenhuma verificação de autorização. Todos os arquivos servidos pelo Static File Middleware, incluindo aqueles sob wwwroot, estão disponíveis publicamente. Para obter uma abordagem para proteger arquivos estáticos, consulte Arquivos estáticos no ASP.NET Core.

Se a solicitação não for tratada pelo Middleware de Arquivo Estático, ela será passada para o Middleware de Autenticação (UseAuthentication), que executa a autenticação. A autenticação não provoca curto-circuito em solicitações não autenticadas. Embora o Middleware de Autenticação autentique solicitações, a autorização (e a rejeição) ocorre apenas após o MVC selecionar uma página específica identificada por Razor ou um controlador e uma ação de MVC específicos.

O exemplo a seguir demonstra uma ordem de middleware em que as solicitações de arquivos estáticos são tratadas pelo Static File Middleware antes do Response Compression Middleware. Os arquivos estáticos não são compactados com essa ordem de middleware. As respostas do Razor Pages podem ser compactadas.

public void Configure(IApplicationBuilder app)
{
    // Static files aren't compressed by Static File Middleware.
    app.UseStaticFiles();

    app.UseRouting();

    app.UseResponseCompression();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Para aplicações de página única (SPAs), o middleware SPA UseSpaStaticFiles geralmente é colocado por último no pipeline de middleware. O middleware SPA vem por último:

  • Para permitir que todos os outros middlewares respondam primeiro às solicitações correspondentes.
  • Para permitir que SPAs com roteamento do lado do cliente sejam executados para todas as rotas que não são reconhecidas pelo aplicativo do servidor.

Para obter mais detalhes sobre SPAs, consulte os guias dos modelos de projeto React e Angular.

Ordem de middleware de cabeçalhos encaminhados

O Middleware de Cabeçalhos Encaminhados deve ser executado antes dos outros middleware. Essa ordenação garante que o middleware que depende das informações de cabeçalhos encaminhados possa consumir os valores de cabeçalho para processamento. Para correr o middleware de cabeçalhos encaminhados após o middleware de diagnóstico e tratamento de erros, consulte ordem do middleware de cabeçalhos encaminhados.

Ramificar o pipeline de middleware

Extensões Map são usadas como uma convenção para ramificar o pipeline. Map ramifica o pipeline de solicitação com base nas correspondências do caminho de solicitação fornecido. Se o caminho da solicitação começar com o caminho fornecido, a ramificação será executada.

public class Startup
{
    private static void HandleMapTest1(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 1");
        });
    }

    private static void HandleMapTest2(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 2");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1", HandleMapTest1);

        app.Map("/map2", HandleMapTest2);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate.");
        });
    }
}

A tabela a seguir mostra as solicitações e respostas de http://localhost:1234 usando o código anterior.

Solicitar Resposta
localhost:1234 Olá do delegado que não pertence ao Mapa.
localhost:1234/mapa1 Teste de Mapa 1
localhost:1234/map2 Teste de Mapa 2
localhost:1234/map3 Olá do delegado fora do Mapa.

Quando Map é usado, os segmentos de caminho correspondentes são removidos do HttpRequest.Path e anexados ao HttpRequest.PathBase para cada solicitação.

Map suporta aninhamento, por exemplo:

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

Map também pode corresponder a vários segmentos ao mesmo tempo:

public class Startup
{
    private static void HandleMultiSeg(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map multiple segments.");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1/seg1", HandleMultiSeg);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate.");
        });
    }
}

MapWhen ramifica o pipeline de solicitação com base no resultado do predicado dado. Qualquer predicado do tipo Func<HttpContext, bool> pode ser usado para mapear solicitações para uma nova ramificação do pipeline. No exemplo a seguir, um predicado é usado para detetar a presença de uma variável de cadeia de caracteres de consulta branch:

public class Startup
{
    private static void HandleBranch(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            var branchVer = context.Request.Query["branch"];
            await context.Response.WriteAsync($"Branch used = {branchVer}");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.MapWhen(context => context.Request.Query.ContainsKey("branch"),
                               HandleBranch);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate.");
        });
    }
}

A tabela a seguir mostra as solicitações e respostas de http://localhost:1234 usando o código anterior:

Pedido Resposta
localhost:1234 Olá do representante não-Mapa.
localhost:1234/?branch=main Ramificação utilizada = principal

UseWhen também ramifica o pipeline de solicitação com base no resultado do predicado dado. Ao contrário do MapWhen, essa ramificação é unida novamente ao pipeline principal se não houver curto-circuito ou contiver um middleware de terminal:

public class Startup
{
    private void HandleBranchAndRejoin(IApplicationBuilder app, ILogger<Startup> logger)
    {
        app.Use(async (context, next) =>
        {
            var branchVer = context.Request.Query["branch"];
            logger.LogInformation("Branch used = {branchVer}", branchVer);

            // Do work that doesn't write to the Response.
            await next();
            // Do other work that doesn't write to the Response.
        });
    }

    public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
    {
        app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
                               appBuilder => HandleBranchAndRejoin(appBuilder, logger));

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from main pipeline.");
        });
    }
}

No exemplo anterior, uma resposta de "Olá do pipeline principal." é dada para todas as solicitações. Se a solicitação incluir um parâmetro de consulta branch, o seu valor será registado antes que o pipeline principal seja retomado.

Middleware integrado

ASP.NET Core é fornecido com os seguintes componentes de middleware. A coluna Order fornece notas sobre o posicionamento do middleware no pipeline de processamento de solicitações e em que condições o middleware pode encerrar o processamento de solicitações. Quando um middleware interrompe o pipeline de processamento de solicitações e impede que outros middleware posteriores processem uma solicitação, é chamado de middleware terminal . Para obter mais informações sobre curto-circuito, consulte a seção Criar um pipeline de middleware com IApplicationBuilder.

Middleware Descrição Encomenda
autenticação Fornece suporte à autenticação. Antes de HttpContext.User ser necessário. Terminal para retornos de chamada OAuth.
Autorização Fornece suporte de autorização. Imediatamente após o middleware de autenticação.
Política Cookie Rastreia o consentimento dos utilizadores para armazenar informações pessoais e impõe padrões mínimos para campos cookie, como secure e SameSite. Antes do middleware que emite cookies. Exemplos: Autenticação, Sessão, MVC (TempData).
CORS Configura o compartilhamento de recursos entre origens. Antes de componentes que usam CORS. UseCors atualmente deve ir antes de UseResponseCaching devido a este bug .
Diagnóstico Vários middlewares separados que fornecem uma página de exceção do desenvolvedor, tratamento de exceções, páginas de código de status e a página da Web padrão para novos aplicativos. Antes de componentes que geram erros. Terminal para tratamento de exceções ou fornecer a página web padrão para novas aplicações.
Cabeçalhos encaminhados Encaminha cabeçalhos com proxy para a solicitação atual. Antes dos componentes que consomem os campos atualizados. Exemplos: esquema, host, IP do cliente, método.
Verificação de Saúde Verifica a integridade de um aplicativo ASP.NET Core e suas dependências, como verificar a disponibilidade do banco de dados. Terminal se um pedido corresponder a um endpoint de verificação de saúde.
Propagação de Cabeçalho Propaga cabeçalhos HTTP da solicitação de entrada para as solicitações de cliente HTTP de saída.
Substituição de Método HTTP Permite que uma solicitação POST de entrada substitua o método. Antes dos componentes que utilizam o método atualizado.
Redirecionamento HTTPS Redirecionar todas as solicitações HTTP para HTTPS. Antes dos componentes que consomem a URL.
Segurança de Transporte Rígida HTTP (HSTS) Middleware de aprimoramento de segurança que adiciona um cabeçalho de resposta especial. Antes das respostas serem enviadas e depois dos componentes que modificam as solicitações. Exemplos: cabeçalhos encaminhados, reescrita de URL.
MVC Processa solicitações com MVC/Razor Pages. Terminal se um pedido corresponder a uma rota.
OWIN Interoperabilidade com aplicativos, servidores e middleware baseados em OWIN. Terminal se o OWIN Middleware processar totalmente a solicitação.
Cache de Resposta Fornece suporte para respostas em cache. Antes dos componentes que necessitam de cache. UseCORS deve vir antes UseResponseCaching.
Compressão de Resposta Fornece suporte para compressão de respostas. Antes de componentes que requerem compressão.
Solicitar localização Fornece suporte à localização. Antes da localização de componentes sensíveis. Deve aparecer após o Routing Middleware ao usar RouteDataRequestCultureProvider.
Roteamento de Endpoint Define e restringe rotas de solicitação. Terminal para correspondência de itinerários.
SPA Processa todas as solicitações a partir deste ponto na cadeia de middleware ao devolver a página padrão para a Aplicação de Página Única (SPA) No final da cadeia, para que o outro middleware que serve arquivos estáticos, ações MVC, etc., tenha precedência.
Sessão Fornece suporte para gerenciar sessões de usuário. Antes de componentes que requerem sessão.
arquivos estáticos Fornece suporte para servir arquivos estáticos e navegação em diretórios. Terminal se uma solicitação corresponder a um arquivo.
Reescrita de URL Fornece suporte para reescrever URLs e redirecionar solicitações. Antes dos componentes que consomem a URL.
WebSockets Habilita o protocolo WebSocket. Antes dos componentes necessários para aceitar solicitações WebSocket.

Recursos adicionais