Novidades do ASP.NET Core 8.0

Este artigo destaca as alterações mais significativas no ASP.NET Core 8.0, com links para a documentação relevante.

Blazor

Interface do usuário da Web de pilha completa

Com o lançamento do .NET 8, Blazor é uma estrutura de interface do usuário da Web de pilha completa para o desenvolvimento de aplicativos que renderizam o conteúdo no nível do componente ou da página com:

  • Renderização de servidor estático (também chamado de renderização estática do lado do servidor, SSR estático) para gerar HTML estático no servidor.
  • Renderização interativa do Servidor (também chamada de renderização interativa do lado do servidor, SSR interativa) para gerar componentes interativos com a pré-geração no servidor.
  • Renderização interativa do WebAssembly (também chamada de renderização do lado do cliente, CSR, que sempre é considerada interativa) para gerar componentes interativos no cliente com pré-geração no servidor.
  • Renderização automática interativa (automática) para usar inicialmente o runtime do ASP.NET Core do servidor para renderização de conteúdo e interatividade. O runtime do .NET WebAssembly no cliente é usado para renderização e interatividade subsequentes depois que o pacote Blazor é baixado e o runtime do WebAssembly é ativado. A renderização automática interativa geralmente oferece a experiência de inicialização de aplicativo mais rápida.

Os modos de renderização interativa também pré-renderizam o conteúdo por padrão.

Para obter mais informações, consulte os seguintes artigos:

Exemplos em toda a documentação Blazor foram atualizados para uso em Aplicativos Web Blazor. Exemplos Blazor Server permanecem no conteúdo com versão para .NET 7 ou anterior.

Novo artigo sobre bibliotecas de classes com renderização estática do lado do servidor (SSR estático)

Adicionamos um novo artigo que discute a autoria da biblioteca de componentes em RCLs (bibliotecas de classes) no Razor com renderização estática do lado do servidor (SSR estático).

Para obter mais informações, consulte Bibliotecas de classes (RCLs) do ASP.NET Core Razor com renderização estática do lado do servidor (SSR estático).

Novo artigo sobre problemas de cache HTTP

Adicionamos um novo artigo que discute alguns dos problemas comuns de cache HTTP que podem ocorrer ao atualizar Blazor aplicativos entre as versões principais e como resolver problemas de cache HTTP.

Para obter mais informações, confira Evitar problemas de cache HTTP ao atualizar aplicativos ASP.NET Core Blazor.

Novo Modelo de aplicativo Web Blazor

Introduzimos um novo modelo de projeto Blazor: o modelo Blazor Aplicativo Web. O novo modelo oferece um único ponto de partida para o uso de componentes Blazor para criar qualquer estilo de interface de usuário da Web. O modelo combina os pontos fortes dos modelos de hospedagem Blazor Server e Blazor WebAssembly existentes com os novos recursos Blazor adicionados ao .NET 8: renderização do lado do servidor estático (SSR estático), renderização de fluxo, navegação aprimorada e manipulação de formulários, além da capacidade de adicionar interatividade usando Blazor Server ou Blazor WebAssembly por componente.

Como parte da unificação dos vários modelos de hospedagem Blazor em um único modelo no .NET 8, também estamos consolidando o número de modelos de projeto Blazor. Removemos o modelo Blazor Server e a opção Hospedagem do ASP.NET Core foi removida do modelo Blazor WebAssembly. Esses dois cenários são representados por opções ao usar o modelo de aplicativo Web Blazor.

Observação

Os aplicativos Blazor Server e Blazor WebAssembly existentes permanecem compatíveis com o .NET 8. Opcionalmente, esses aplicativos podem ser atualizados para utilizar os novos recursos Blazor da interface do usuário da Web de pilha completa.

Para obter mais informações sobre o novo aplicativo Web Blazor, consulte os artigos a seguir:

Novos inicializadores JS para aplicativos Web Blazor

Para aplicativos Blazor Server, Blazor WebAssembly e Blazor Hybrid:

  • beforeStart é usado para tarefas como personalizar o processo de carregamento, o nível de log e outras opções.
  • afterStarted é usado para tarefas como registrar ouvintes de eventos Blazor e tipos de eventos personalizados.

Os inicializadores herdados JS anteriores não são invocados por padrão em um aplicativo Web do Blazor. Para Blazor aplicativos Web, um novo conjunto de inicializadores JS é usado: beforeWebStart, afterWebStarted, beforeServerStart, afterServerStarted, beforeWebAssemblyStarte afterWebAssemblyStarted.

Para obter mais informações, confira Inicialização Blazor do ASP.NET Core.

Divisão de diretrizes de pré-geração e integração

Para versões anteriores do .NET, abordamos a pré-geração e a integração em um único artigo. Para simplificar e concentrar nossa cobertura, dividimos os assuntos nos novos artigos a seguir, que foram atualizados para o .NET 8:

Persistir o estado do componente em um aplicativo Web Blazor

Você pode persistir e ler o estado do componente em um aplicativo Web Blazor usando o serviço PersistentComponentState existente. Isso é útil para persistir o estado do componente durante a pré-renderização.

Os Aplicativos Web Blazor persistem automaticamente qualquer estado de nível de aplicativo registrado durante a pré-renderização, removendo a necessidade do Auxiliar de marca de estado de persistência de componente.

Tratamento de formulários e model binding

Os componentes Blazor agora podem tratar as solicitações dos formulários enviados, incluindo o model binding e a validação dos dados da solicitação. Os componentes podem implementar formulários com manipuladores de formulários separados usando a marca HTML <form> padrão ou usando o componente EditForm existente.

O model binding de formulário em Blazor respeita os atributos de contrato de dados (por exemplo, [DataMember] e [IgnoreDataMember]) para personalizar como os dados do formulário são associados ao modelo.

O novo suporte a antifalsificação está incluído no .NET 8. Um novo componente AntiforgeryToken renderiza um token antifalsificação como um campo oculto, e o novo atributo [RequireAntiforgeryToken] habilita a proteção anti-falsificação. Se uma verificação antifalsificação falhar, uma resposta 400 (Solicitação Incorreta) será retornada sem o processamento do formulário. Os novos recursos antifalsificação estão ativados por padrão para formulários baseados em Editform e podem ser aplicados manualmente a formulários HTML padrão.

Para obter mais informações, consulte ASP.NET CoreBlazor Visão geral dos formulários.

Navegação e tratamento de formulários aprimorados

A renderização estática do lado do servidor (SSR estático) normalmente executa uma atualização completa da página sempre que o usuário navega para uma nova página ou envia um formulário. No .NET 8, Blazor pode aprimorar a navegação da página e o tratamento de formulários interceptando a solicitação e, em vez disso, executando uma solicitação de busca. Em seguida, Blazor manipula o conteúdo da resposta renderizada, inserindo-o no DOM do navegador. A navegação e o tratamento de formulários aprimorados evitam a necessidade de uma atualização completa da página e preservam mais do estado da página, de modo que as páginas são carregadas mais rapidamente e de forma mais suave. A navegação aprimorada é habilitada por padrão quando o script Blazor (blazor.web.js) é carregado. O tratamento aprimorado de formulários pode ser habilitado opcionalmente para formulários específicos.

A nova API de navegação aprimorada permite que você atualize a página atual chamando NavigationManager.Refresh(bool forceLoad = false).

Para obter mais informações, confira as seções abaixo do artigo BlazorRoteamento:

Novo artigo sobre renderização estática com navegação aprimorada para interoperabilidade JS

Alguns aplicativos dependem da interoperabilidade JS para executar tarefas de inicialização específicas para cada página. Ao usar o recurso de navegação avançado do Blazor com páginas renderizadas estaticamente que executam tarefas de inicialização de interoperabilidade JS, o JS específico da página pode não ser executado novamente conforme o esperado sempre que ocorrer uma navegação de página aprimorada. Um novo artigo explica como lidar com esse cenário nos Aplicativos Web Blazor:

ASP.NET Core Blazor JavaScript com renderização estática do lado do servidor (SSR estática)

Renderização de streaming

Agora você pode transmitir atualizações de conteúdo no fluxo de resposta ao usar a renderização estática do servidor (SSR estática) com Blazor. A renderização do fluxo pode melhorar a experiência do usuário em páginas que executam tarefas assíncronas de longa execução para renderizar totalmente o conteúdo assim que ele estiver disponível.

Por exemplo, para renderizar uma página, talvez seja necessário fazer uma consulta de banco de dados de execução prolongada ou uma chamada de API. Normalmente, as tarefas assíncronas executadas como parte da renderização de uma página devem ser concluídas antes que a resposta renderizada seja enviada, o que pode atrasar o carregamento da página. A renderização do streaming inicialmente renderiza a página inteira com o conteúdo do espaço reservado enquanto as operações assíncronas são executadas. Depois que as operações assíncronas são concluídas, o conteúdo atualizado é enviado ao cliente na mesma conexão de resposta e corrigido no DOM. A vantagem dessa abordagem é que o layout principal do aplicativo é renderizado o mais rápido possível e a página é atualizada assim que o conteúdo estiver pronto.

Para saber mais, consulte Renderização de componentes de Razor no ASP.NET Core.

Injetar serviços com chave em componentes

Blazor agora dá suporte à injeção de serviços com chave usando o atributo [Inject]. As chaves permitem o escopo do registro e do consumo de serviços ao usar a injeção de dependência. Use a nova propriedade InjectAttribute.Key para especificar a chave para o serviço injetar:

[Inject(Key = "my-service")]
public IMyService MyService { get; set; }

A diretiva do @injectRazor não dá suporte a serviços chave para esta versão, mas o trabalho é acompanhado pela Atualização @inject para dar suporte a serviços chaveados (dotnet/razor #9286) para uma versão futura do .NET.

Para saber mais, confira Injeção de dependência do Blazor no ASP.NET Core.

Acesse HttpContext como um parâmetro em cascata

Agora você pode acessar o HttpContext atual como um parâmetro em cascata de um componente de servidor estático:

[CascadingParameter]
public HttpContext? HttpContext { get; set; }

O acesso a HttpContext de um componente de servidor estático pode ser útil para inspecionar e modificar cabeçalhos ou outras propriedades.

Para obter um exemplo que transmite o estado de HttpContext, o acesso e os tokens de atualização para os componentes, confira Cenários de segurança do Blazor no ASP.NET Core do lado do servidor. adicionais.

Renderizar componentes Razor fora do ASP.NET Core

Agora você pode renderizar os componentes Razor fora do contexto de uma solicitação HTTP. Você pode renderizar componentes Razor como HTML diretamente em uma cadeia de caracteres ou transmitir independentemente do ambiente de hospedagem do ASP.NET Core. Isso é conveniente para cenários em que você deseja gerar fragmentos de HTML, como para gerar um email ou conteúdo de site estático.

Para obter mais informações, consulte Renderizar Razor componentes fora do ASP.NET Core.

Suporte a seções

Os novos componentes SectionOutlet e SectionContent em Blazor adicionam suporte para especificar saídas para o conteúdo que pode ser preenchido posteriormente. As seções são frequentemente usadas para definir espaços reservados em layouts que são preenchidos por páginas específicas. As seções são referenciadas por um nome exclusivo ou usando uma ID de objeto exclusiva.

Para obter mais informações, consulte ASP.NET Core Blazor seções.

Suporte da página de erro

Os Aplicativos Web Blazor podem definir uma página de erro personalizada para uso com o middleware de tratamento de exceção do ASP.NET Core. O modelo de projeto de aplicativo Web Blazor inclui uma página de erro padrão (Components/Pages/Error.razor) com conteúdo semelhante ao usado em aplicativos MVC e Razor Pages. Quando a página de erro é renderizada em resposta a uma solicitação do Middleware de Tratamento de Exceções, a página de erro sempre é renderizada como um componente de servidor estático, mesmo se a interatividade estiver habilitada de outra forma.

Error.razor na fonte de referência 8.0

QuickGrid

O componente QuickGrid Blazor não é mais experimental e agora faz parte da estrutura Blazor no .NET 8.

O QuickGrid é um componente de grade de alto desempenho para a exibição de dados em forma de tabela. O QuickGrid foi criado para ser uma forma simples e conveniente de exibir seus dados, ao mesmo tempo em que oferece recursos avançados, como classificação, filtragem, paginação e virtualização.

Para saber mais, confira Componente QuickGrid do Blazor no ASP.NET Core.

Rota para elementos nomeados

Blazor agora tem suporte para o uso do roteamento do lado do cliente para navegar até um elemento HTML específico em uma página usando fragmentos de URL padrão. Se você especificar um identificador para um elemento HTML usando o atributo padrão id, Blazor rolará corretamente para esse elemento quando o fragmento de URL corresponder ao identificador do elemento.

Para obter mais informações, confira Roteamento e navegação do Blazor no ASP.NET Core.

Valores em cascata no nível raiz

Os valores em cascata no nível raiz podem ser registrados para toda a hierarquia de componentes. Há suporte para valores em cascata nomeados e assinaturas para notificações de atualização.

Para obter mais informações, confira Valores em cascata e parâmetros Blazor do ASP.NET Core.

Virtualizar conteúdo vazio

Use o novo parâmetro EmptyContent no componente Virtualize para fornecer conteúdo quando o componente tiver sido carregado e Items estiver vazio ou ItemsProviderResult<T>.TotalItemCount for zero.

Para obter mais informações, confira Virtualização de componentes Razor do ASP.NET Core.

Fechar circuitos quando não houver componentes de servidor interativos restantes

Os componentes interativos do servidor lidam com eventos de interface do usuário da Web usando uma conexão em tempo real com o navegador chamada de circuito. Um circuito e seu estado associado são configurados quando um componente de servidor interativo raiz é renderizado. O circuito é fechado quando não existem componentes de servidor interativos restantes na página, o que libera recursos do servidor.

Monitorar a atividade do circuito SignalR

Agora você pode monitorar a atividade do circuito de entrada em aplicativos do lado do servidor usando o novo método CreateInboundActivityHandler em CircuitHandler. Uma atividade de circuito de entrada é qualquer atividade enviada do navegador para o servidor, como eventos de interface do usuário ou chamadas de interoperabilidade JavaScript para o .NET.

Para obter mais informações, confira as diretrizes BlazorSignalRdo ASP.NET Core.

Desempenho mais rápido do runtime com o Jiterpreter

O Jiterpreter é um novo recurso de runtime no .NET 8 que permite o suporte parcial à compilação Just-in-Time (JIT) ao ser executado no WebAssembly para obter o melhor desempenho do runtime.

Para obter mais informações, confira Hospedar e implantar Blazor WebAssembly do ASP.NET Core.

SIMD do (AOT) antecipado e tratamento de exceções

Blazor WebAssemblyA compilação (AOT) antecipada agora usa o SIMD de largura Fixa do WebAssembly e o tratamento de Exceções do WebAssembly por padrão para melhorar o desempenho do runtime.

Para obter mais informações, consulte os seguintes artigos:

Empacotamento do Webcil Amigável à Web

O Webcil é um empacotamento amigável para a Web de assemblies do .NET que remove o conteúdo específico da execução nativa do Windows para evitar problemas ao implantar em ambientes que bloqueiam o download ou o uso de arquivos .dll. O Webcil está habilitado por padrão para aplicativos Blazor WebAssembly.

Para obter mais informações, confira Hospedar e implantar Blazor WebAssembly do ASP.NET Core.

Observação

Antes do lançamento do .NET 8, a orientação em Layout de implantação para aplicativos hospedados Blazor WebAssembly do ASP.NET Core aborda ambientes que impedem os clientes de baixar e executar DLLs com uma abordagem de agrupamento de várias partes. No .NET 8 ou posterior, Blazor usa o formato de arquivo Webcil para resolver esse problema. O agrupamento de várias partes usando o pacote NuGet experimental descrito pelo artigo Layout de implantação do WebAssembly não tem suporte para aplicativos Blazor no .NET 8 ou posterior. Para obter mais informações, consulte Aprimorar Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle o pacote para definir um formato de pacote personalizado (dotnet/aspnetcore #36978). Se você quiser continuar usando o pacote de várias partes em aplicativos .NET 8 ou posteriores, poderá usar as diretrizes no artigo para criar seu próprio pacote NuGet de agrupamento de várias partes, mas ele não terá suporte da Microsoft.

Melhorias na depuração do Blazor WebAssembly

Ao depurar o .NET no WebAssembly, o depurador agora faz download de dados de símbolos de locais de símbolos configurados nas preferências do Visual Studio. Isso melhora a experiência de depuração para aplicativos que utilizam pacotes NuGet.

Agora você pode depurar aplicativos Blazor WebAssembly usando o Firefox. A depuração de aplicativos Blazor WebAssembly exige a configuração do navegador para depuração remota e, em seguida, a conexão com o navegador usando as ferramentas de desenvolvedor do navegador por meio do proxy de depuração do .NET WebAssembly. A depuração do Firefox a partir do Visual Studio não é suportada no momento.

Para obter mais informações, consulte Depuração de aplicativos ASP.NET Core Blazor.

Compatibilidade com a Política de Segurança de Conteúdo (CSP)

O Blazor WebAssembly não exige mais a ativação da fonte do script unsafe-eval ao especificar uma Política de Segurança de Conteúdo (CSP).

Para obter mais informações, confira Impor uma política de segurança de conteúdo para Blazor ASP.NET Core.

Manipular exceções capturadas fora do ciclo de vida de um componente Razor

Use ComponentBase.DispatchExceptionAsync em um componente Razor para processar exceções geradas fora da pilha de chamadas do ciclo de vida do componente. Isso permite que o código do componente trate exceções como se fossem exceções de método de ciclo de vida. Depois disso, os mecanismos de tratamento de erros do Blazor, como limites de erro, podem processar exceções.

Para obter mais informações, confira Resolver erros nos aplicativos do BlazorASP.NET Core.

Configurar o runtime do .NET WebAssembly

Atualmente, o runtime do .NET WebAssembly pode ser configurado para Blazor inicialização.

Para obter mais informações, confira Inicialização Blazor do ASP.NET Core.

Configuração de tempos limite de conexão em HubConnectionBuilder

As soluções alternativas anteriores para configurar os tempos limite de conexão do hub podem ser substituídas pela configuração formal do tempo limite do construtor de conexões do hub SignalR.

Para saber mais, consulte o seguinte:

Modelos de projeto lançados no Open Iconic

Os modelos de projeto Blazor não dependem mais do Open Iconic para ícones.

Suporte para eventos de cancelamento e fechamento de caixa de diálogo

Blazor agora dá suporte aoa eventos cancel e close no elemento HTML dialog.

No exemplo a seguir:

  • OnClose é chamado quando a caixa de diálogo my-dialog é fechada com o botão Fechar.
  • OnCancel é chamado quando a caixa de diálogo é cancelada com a chave Esc. Quando uma caixa de diálogo HTML é descartada com a chave Esc, os eventos e os eventos cancel e close são disparados.
<div>
    <p>Output: @message</p>

    <button onclick="document.getElementById('my-dialog').showModal()">
        Show modal dialog
    </button>

    <dialog id="my-dialog" @onclose="OnClose" @oncancel="OnCancel">
        <p>Hi there!</p>

        <form method="dialog">
            <button>Close</button>
        </form>
    </dialog>
</div>

@code {
    private string? message;

    private void OnClose(EventArgs e) => message += "onclose, ";

    private void OnCancel(EventArgs e) => message += "oncancel, ";
}

BlazorIdentity IU

Blazor dá suporte à geração de uma interface do usuário Identity completa baseada em Blazor quando você escolhe a opção de autenticação para Contas Individuais. Você pode selecionar a opção de Contas Individuais na caixa de diálogo de novo projeto para Aplicativos Web Blazor do Visual Studio, ou passar a opção -au|--auth configurada como Individual na linha de comando ao criar um novo projeto.

Para saber mais, consulte os recursos a seguir:

Proteger Blazor WebAssembly com ASP.NET Core Identity

A documentação do Blazor hospeda um novo artigo e um aplicativo de exemplo para cobrir a proteção de um aplicativo autônomo Blazor WebAssembly com o ASP.NET Core Identity.

Para saber mais, consulte os recursos a seguir:

Blazor Server com roteamento Yarp

O roteamento e a associação profunda para Blazor Server com o Yarp funcionam corretamente no .NET 8.

Para obter mais informações, consulte Migrar do ASP.NET Core 7.0 para o 8.0.

Blazor Hybrid

Os seguintes artigos documentam alterações para Blazor Hybrid no .NET 8:

  • Solucionar problemas ASP.NET Core Blazor Hybrid: um novo artigo explica como usar o registro em log do BlazorWebView.
  • Criar um .NET MAUIaplicativo do Blazor Hybrid: O nome do modelo de projeto .NET MAUI Blazor foi alterado para .NET MAUI Blazor Hybrid.
  • ASP.NET Core Blazor Hybrid: BlazorWebView obtém um método TryDispatchAsync que chama um Action<ServiceProvider> especificado de forma assíncrona e passa nos serviços com escopo disponíveis em componentes Razor. Isso permite que o código da interface do usuário nativa acesse serviços com escopo, como NavigationManager.
  • Roteamento e navegação do ASP.NET CoreBlazor Hybrid: use a propriedade BlazorWebView.StartPath para obter ou definir o caminho para a navegação inicial dentro do contexto de navegação do Blazor quando o componente Razor terminar de carregar.

O atributo [Parameter] não é mais necessário quando fornecido da cadeia de caracteres de consulta

O atributo [Parameter] não é mais necessário ao fornecer um parâmetro da cadeia de caracteres de consulta:

- [Parameter]
  [SupplyParameterFromQuery]

SignalR

Nova abordagem para definir o tempo limite do servidor e o intervalo Keep-Alive

ServerTimeout (padrão: 30 segundos) e KeepAliveInterval (padrão: 15 segundos) podem ser definidos diretamente em HubConnectionBuilder.

Abordagem anterior para clientes JavaScript

O exemplo a seguir mostra a atribuição de valores que são o dobro dos valores padrão no ASP.NET Core 7.0 ou anterior:

var connection = new signalR.HubConnectionBuilder()
  .withUrl("/chatHub")
  .build();

connection.serverTimeoutInMilliseconds = 60000;
connection.keepAliveIntervalInMilliseconds = 30000;

Nova abordagem para clientes JavaScript

O exemplo a seguir mostra a nova abordagem para atribuir valores que são o dobro dos valores padrão no ASP.NET Core 8.0 ou posterior:

var connection = new signalR.HubConnectionBuilder()
  .withUrl("/chatHub")
  .withServerTimeout(60000)
  .withKeepAlive(30000)
  .build();

Abordagem anterior para o cliente JavaScript de um aplicativo Blazor Server

O exemplo a seguir mostra a atribuição de valores que são o dobro dos valores padrão no ASP.NET Core 7.0 ou anterior:

Blazor.start({
  configureSignalR: function (builder) {
    let c = builder.build();
    c.serverTimeoutInMilliseconds = 60000;
    c.keepAliveIntervalInMilliseconds = 30000;
    builder.build = () => {
      return c;
    };
  }
});

Nova abordagem para o cliente JavaScript de um aplicativo Blazor do lado do servidor

O exemplo a seguir mostra a nova abordagem para atribuir valores que são o dobro dos valores padrão no ASP.NET Core 8.0 ou posterior para Blazor Aplicativos Web e Blazor Server.

Aplicativo Web Blazor:

Blazor.start({
  circuit: {
    configureSignalR: function (builder) {
      builder.withServerTimeout(60000).withKeepAliveInterval(30000);
    }
  }
});

Blazor Server:

Blazor.start({
  configureSignalR: function (builder) {
    builder.withServerTimeout(60000).withKeepAliveInterval(30000);
  }
});

Abordagem prévia para clientes .NET

O exemplo a seguir mostra a atribuição de valores que são o dobro dos valores padrão no ASP.NET Core 7.0 ou anterior:

var builder = new HubConnectionBuilder()
    .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
    .Build();

builder.ServerTimeout = TimeSpan.FromSeconds(60);
builder.KeepAliveInterval = TimeSpan.FromSeconds(30);

builder.On<string, string>("ReceiveMessage", (user, message) => ...

await builder.StartAsync();

Nova abordagem para clientes .NET

O exemplo a seguir mostra a nova abordagem para atribuir valores que são o dobro dos valores padrão no ASP.NET Core 8.0 ou posterior:

var builder = new HubConnectionBuilder()
    .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
    .WithServerTimeout(TimeSpan.FromSeconds(60))
    .WithKeepAliveInterval(TimeSpan.FromSeconds(30))
    .Build();

builder.On<string, string>("ReceiveMessage", (user, message) => ...

await builder.StartAsync();

SignalR reconexão com estado

SignalRA reconexão com estado reduz o tempo de inatividade percebido dos clientes que têm uma desconexão temporária em sua conexão de rede, como ao alternar as conexões de rede ou uma breve perda temporária de acesso.

A reconexão com estado alcança esse objetivo:

  • Armazenando dados em buffer temporariamente no servidor e no cliente.
  • Confirmando mensagens recebidas (ACK-ing) pelo servidor e pelo cliente.
  • Reconhecendo quando uma conexão está retornando e reproduzindo mensagens que podem ter sido enviadas enquanto a conexão estava inativa.

A reconexão com estado está disponível no ASP.NET Core 8.0 e posterior.

Aceite se reconectar com estado no ponto de extremidade do hub de servidor e no cliente:

  • Atualize a configuração do ponto de extremidade do hub de servidor para habilitar a opção AllowStatefulReconnects :

    app.MapHub<MyHub>("/hubName", options =>
    {
        options.AllowStatefulReconnects = true;
    });
    

    Opcionalmente, o tamanho máximo do buffer em bytes permitidos pelo servidor pode ser definido globalmente ou para um hub específico com a opção StatefulReconnectBufferSize:

    A opção StatefulReconnectBufferSize definida globalmente:

    builder.AddSignalR(o => o.StatefulReconnectBufferSize = 1000);
    

    A opção StatefulReconnectBufferSize definida para um hub específico:

    builder.AddSignalR().AddHubOptions<MyHub>(o => o.StatefulReconnectBufferSize = 1000);
    

    A opção StatefulReconnectBufferSize é opcional com um padrão de 100.000 bytes.

  • Atualize o código do cliente JavaScript ou TypeScript para habilitar a opção withStatefulReconnect:

    const builder = new signalR.HubConnectionBuilder()
      .withUrl("/hubname")
      .withStatefulReconnect({ bufferSize: 1000 });  // Optional, defaults to 100,000
    const connection = builder.build();
    

    A opção bufferSize é opcional com um padrão de 100.000 bytes.

  • Atualize o código do cliente .NET para habilitar a opção WithStatefulReconnect:

      var builder = new HubConnectionBuilder()
          .WithUrl("<hub url>")
          .WithStatefulReconnect();
      builder.Services.Configure<HubConnectionOptions>(o => o.StatefulReconnectBufferSize = 1000);
      var hubConnection = builder.Build();
    

    A opção StatefulReconnectBufferSize é opcional com um padrão de 100.000 bytes.

Para saber mais, consulte Configurar a reconexão com estado.

APIs mínimas

Essa seção descreve novos recursos para APIs mínimas. Consulte também a seção sobre AOT Nativo para obter mais informações relevantes sobre APIs mínimas.

Cultura de substituição do usuário

A partir do ASP.NET Core 8.0, a propriedade RequestLocalizationOptions.CultureInfoUseUserOverride permite que o aplicativo decida se deve ou não usar configurações não padrão do Windows para as propriedades CultureInfoDateTimeFormat e NumberFormat. Isso não afeta o Linux. Isso corresponde diretamente a UseUserOverride.

    app.UseRequestLocalization(options =>
    {
        options.CultureInfoUseUserOverride = false;
    });

Associação a formulários

Agora há suporte para associação explícita a valores de formulário usando o atributo [FromForm ]. Os parâmetros associados à solicitação com [FromForm] incluem um token anti-falsificação. O token antifalsificação é validado quando a solicitação é processada.

Associação inferida a formulários usando os tipos IFormCollection, IFormFilee IFormFileCollection também são compatíveis. Metadados da OpenAPI são inferidos para parâmetros de formulário para dar suporte à integração com a interface do usuário do Swagger.

Para obter mais informações, consulte:

A associação de formulários agora tem suporte para:

  • Coleções, por exemplo, Lista e Dicionário
  • Tipos complexos, por exemplo, Todo ou Project

Para obter mais informações, consulte Associar a coleções e tipos complexos de formulários.

Antifalsificação com o mínimo de APIs

Esta versão adiciona um middleware para validar os tokens antifalsificação, que são utilizados para mitigar ataques de falsificação de solicitações entre sites. Chame AddAntiforgery para registrar serviços antifalsificação no DI. WebApplicationBuilder adiciona automaticamente o middleware quando os serviços antifalsificação tiverem sido registrados no contêiner DI. Tokens antifalsificação são usados para atenuar ataques de falsificação de solicitação entre sites.

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

app.MapGet("/", () => "Hello World!");

app.Run();

O middleware antifalsificação:

O token antifalsificação só será validado se:

  • O ponto de extremidade contém metadados que implementam IAntiforgeryMetadata em que RequiresValidation=true.
  • O método HTTP associado ao ponto de extremidade é um método HTTP relevante. Os métodos relevantes são todos métodos HTTP exceto TRACE, OPTIONS, HEAD e GET.
  • A solicitação está associada a um ponto de extremidade válido.

Para obter mais informações, consulte Antifalsificação com APIs mínimas.

Nova interface IResettable em ObjectPool

Microsoft.Extensions.ObjectPool fornece suporte para agrupar instâncias de objeto na memória. Os aplicativos poderão usar um pool de objetos se os valores forem caros para alocar ou inicializar.

Nessa versão, facilitamos o uso do pool de objetos adicionando a interface IResettable. Tipos reutilizáveis geralmente precisam ser redefinidos para um estado padrão entre usos. os tipos IResettable são redefinidos automaticamente quando retornados para um pool de objetos.

Para obter mais informações, consulte o exemplo de ObjectPool.

AOT nativo

O suporte para .NET nativo ahead-of-time (AOT) foi adicionado. Os aplicativos publicados usando o AOT podem ter um desempenho substancialmente melhor: tamanho menor de aplicativo, menos uso de memória e tempo de inicialização mais rápido. Atualmente, o AOT nativo tem suporte para gRPC, API mínima e aplicativos de serviço de trabalho. Para obter mais informações, confira Suporte do ASP.NET Core para AOT Nativo e Tutorial: publicar um aplicativo ASP.NET Core usando o AOT Nativo. Para obter informações sobre problemas conhecidos com a compatibilidade do ASP.NET Core e do AOT Nativo, confira o problema dotnet/core #8288 do GitHub.

Bibliotecas e AOT Nativo

Muitas das bibliotecas populares usadas em projetos do ASP.NET Core atualmente têm alguns problemas de compatibilidade quando usadas em um projeto voltado para o AOT Nativo, como:

  • Uso de reflexão para inspecionar e descobrir tipos.
  • Carregamento condicional de bibliotecas em runtime.
  • Geração de código em tempo real para implementar a funcionalidade.

As bibliotecas que usam esses recursos dinâmicos precisam ser atualizadas para funcionar com o AOT Nativo. Elas podem ser atualizadas usando ferramentas como geradores de origem Roslyn.

Os autores da biblioteca que desejam dar suporte ao AOT nativo são incentivados a:

Novo modelo de projeto

O novo modelo de projeto API Web do ASP.NET Core (AOT Nativo) (nome curto webapiaot) cria um projeto com a publicação AOT habilitada. Para obter mais informações, confira O modelo de API da Web (AOT Nativo).

Novo método CreateSlimBuilder

O método CreateSlimBuilder() usado no modelo de Web API (AOT Nativo) inicializa o WebApplicationBuilder com os recursos mínimos do ASP.NET Core necessários para executar um aplicativo. O método CreateSlimBuilder inclui os seguintes recursos que normalmente são necessários para uma experiência de desenvolvimento eficiente:

  • Configuração de arquivo JSON para appsettings.json e appsettings.{EnvironmentName}.json.
  • Configuração de segredos do usuário.
  • Registro em log de console.
  • Configuração do registro em log.

Para obter mais informações, consulte o método CreateSlimBuilder.

Novo método CreateEmptyBuilder

Há outro novo WebApplicationBuilder método de fábrica para a criação de aplicativos pequenos que contêm apenas os recursos necessários: WebApplication.CreateEmptyBuilder(WebApplicationOptions options). Esse WebApplicationBuilder é criado sem comportamento interno. O aplicativo criado contém apenas os serviços e middleware configurados explicitamente.

Veja um exemplo de como usar essa API para criar um aplicativo Web pequeno:

var builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions());
builder.WebHost.UseKestrelCore();

var app = builder.Build();

app.Use(async (context, next) =>
{
    await context.Response.WriteAsync("Hello, World!");
    await next(context);
});

Console.WriteLine("Running...");
app.Run();

A publicação desse código com o AOT Nativo usando a Versão Prévia 7 do .NET 8 em um computador Linux-x64 resulta em um executável nativo autônomo de cerca de 8,5 MB.

Redução do tamanho do aplicativo com suporte a HTTPS configurável

Reduzimos ainda mais o tamanho do binário do AOT Nativo para aplicativos que não precisam de suporte a HTTPS ou HTTP/3. Não usar HTTPS ou HTTP/3 é comum para aplicativos executados atrás de um proxy de terminação TLS (por exemplo, hospedado no Azure). O novo método WebApplication.CreateSlimBuilder omite essa funcionalidade por padrão. Ele pode ser adicionado chamando builder.WebHost.UseKestrelHttpsConfiguration() para HTTPS ou builder.WebHost.UseQuic() para HTTP/3. Para obter mais informações, consulte o método CreateSlimBuilder.

JSSerialização ON de tipos IAsyncEnumerable<T> gerados por compilador

Novos recursos foram adicionados ao System.Text.Json para dar melhor suporte ao AOT Nativo. Esses novos recursos adicionam funcionalidades para o modo de geração de origem de System.Text.Json porque a reflexão não é suportada pelo AOT.

Um dos novos recursos é o suporte para JSserialização ON de implementações IAsyncEnumerable<T> realizadas pelo compilador C#. Esse suporte abre seu uso em projetos ASP.NET Core configurados para publicar o AOT Nativo.

Essa API é útil em cenários em que um manipulador de rotas usa yield return para retornar de forma assíncrona uma enumeração. Por exemplo, para materializar linhas de uma consulta de banco de dados. Para obter mais informações, consulte Suporte de tipo indescritível no comunicado do .NET 8 versão prévia 4.

Para obter informações, mas outras melhorias na geração de origem System.Text.Json, consulte melhorias de serialização no .NET 8.

APIs de nível superior anotadas para avisos de corte

Os principais pontos de entrada para subsistemas que não funcionam de forma confiável com o AOT Nativo agora estão anotados. Quando esses métodos são chamados em um aplicativo com o AOT Nativo habilitado, um aviso é fornecido. Por exemplo, o código a seguir produz um aviso na invocação de AddControllers, pois essa API não é segura para o corte e não tem suporte no AOT Nativo.

Janela do Visual Studio mostrando a mensagem de aviso IL2026 no método AddControllers que diz que o MVC atualmente não dá suporte ao AOT nativo.

Gerador de delegado de solicitação

Para tornar as APIs Mínimas compatíveis com o AOT Nativo, estamos introduzindo o Gerador de Delegados de Solicitação (RDG). O RDG é um gerador de origem que faz o que o RequestDelegateFactory (RDF) faz. Ou seja, transforma as vários MapGet(), MapPost() e chamadas como elas em instâncias RequestDelegate associadas às rotas especificadas. Mas, em vez de fazer isso na memória em um aplicativo quando ele é iniciado, o RDG o faz em tempo de compilação e gera o código C# diretamente no projeto. O RDG:

  • Remove a geração de runtime desse código.
  • Garante que os tipos usados nas APIs sejam analisáveis estaticamente pela cadeia de ferramentas do AOT Nativo.
  • Garante que o código necessário não seja cortado.

Estamos trabalhando para garantir que o maior número possível de recursos da API mínima tenha suporte no RDG e, portanto, compatível com o AOT Nativo.

O RDG é habilitado automaticamente em um projeto quando a publicação com AOT Nativo está habilitada. O RDG pode ser habilitado manualmente, mesmo quando não estiver usando o AOT Nativo, definindo <EnableRequestDelegateGenerator>true</EnableRequestDelegateGenerator> no arquivo de projeto. Isso pode ser útil ao avaliar inicialmente a prontidão de um projeto para o AOT Nativo ou para reduzir o tempo de inicialização de um aplicativo.

Desempenho aprimorado usando interceptores

O Request Delegate Generator usa o novo recurso do compilador de interceptores do C# 12 para dar suporte à interceptação de chamadas para métodos de ação Map da API mínima com variantes geradas estaticamente em runtime. O uso de interceptores resulta no aumento do desempenho de inicialização para aplicativos compilados com PublishAot.

Registro em log e tratamento de exceções em APIs mínimas geradas em tempo de compilação

ApIs mínimas geradas em tempo de execução dão suporte automaticamente ao registro em log (ou geração de exceções em ambientes de desenvolvimento) quando a associação de parâmetros falha. O .NET 8 apresenta o mesmo suporte para APIs geradas em tempo de compilação por meio do Gerador de Representante de Solicitação (RDG). Para obter mais informações, consulte Registro em log e tratamento de exceções em APIs mínimas geradas em tempo de compilação.

AOT e System.Text.Json

As APIs mínimas são otimizadas para receber e retornar JSpayloads ON usando System.Text.Json, portanto, os requisitos de compatibilidade para JSON e AOT Nativo também se aplicam. A compatibilidade com o AOT nativo requer o uso do gerador de origem System.Text.Json. Todos os tipos aceitos como parâmetros para ou retornados de representantes de solicitação em APIs mínimas devem ser configurados em um JsonSerializerContext registrado por meio da injeção de dependência do ASP.NET Core, por exemplo:

// Register the JSON serializer context with DI
builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});

...

// Add types used in the minimal API app to source generated JSON serializer content
[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{

}

Para obter mais informações sobre a API TypeInfoResolverChain, consulte os seguintes recursos:

Bibliotecas e AOT Nativo

Muitas das bibliotecas comuns disponíveis para projetos do ASP.NET Core atualmente têm alguns problemas de compatibilidade se forem usadas em um projeto direcionado para o AOT Nativo. As bibliotecas populares geralmente dependem dos recursos dinâmicos de reflexão do .NET para inspecionar e descobrir tipos, carregar condicionalmente bibliotecas em runtime e gerar código em tempo real para implementar sua funcionalidade. Essas bibliotecas precisam ser atualizadas para funcionar com o AOT Nativo usando ferramentas como geradores de fontes Roslyn.

Os autores de bibliotecas que desejam aprender mais sobre como preparar suas bibliotecas para o AOT Nativo são incentivados a começar por preparar sua biblioteca para redução e aprender mais sobre os requisitos de compatibilidade com o AOT Nativo.

Kestrel e servidores HTTP.sys

Há vários novos recursos para Kestrel e HTTP.sys.

Suporte para pipes nomeados em Kestrel

Pipes nomeados é uma tecnologia popular para a criação de IPC (comunicação entre processos) entre aplicativos do Windows. Agora você pode criar um servidor IPC usando o .NET, Kestrel e pipes nomeados.

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.ListenNamedPipe("MyPipeName");
});

Para obter mais informações sobre esse recurso e como usar .NET e gRPC para criar um servidor e cliente IPC, consulte comunicação entre processos com gRPC.

Melhorias de desempenho no transporte de pipes nomeados

Melhoramos o desempenho da conexão de pipe nomeado. KestrelO transporte de pipe nomeado agora aceita conexões em paralelo e reutiliza instâncias NamedPipeServerStream.

Hora de criar 100.000 conexões:

  • Antes: 5,916 segundos
  • Após: 2,374 segundos

SUPORTE HTTP/2 por TLS (HTTPS) no macOS no Kestrel

O .NET 8 adiciona suporte à ALPN (Negociação de Protocolo de Camada de Aplicativo) ao macOS. O ALPN é um recurso TLS usado para negociar qual protocolo HTTP uma conexão usará. Por exemplo, a ALPN permite que navegadores e outros clientes HTTP solicitem uma conexão HTTP/2. Esse recurso é especialmente útil para aplicativos gRPC, que exigem HTTP/2. Para obter mais informações, consulte Usar HTTP/2 com o servidor Web Kestrel do ASP.NET Core.

Arquivo de certificado assistindo em Kestrel

Os certificados TLS configurados por caminho agora são monitorados para alterações quando reloadOnChange é passado para KestrelServerOptions.Configure(). Uma alteração no arquivo de certificado é tratada da mesma maneira que uma alteração no caminho configurado (ou seja, os pontos de extremidade são recarregados).

Observe que as exclusões de arquivo não são controladas especificamente, pois elas surgem transitoriamente e travam o servidor se não forem transitórias.

Aviso quando os protocolos HTTP especificados não serão usados

Se o TLS estiver desabilitado e HTTP/1.x estiver disponível, HTTP/2 e HTTP/3 serão desabilitados, mesmo que tenham sido especificados. Isso pode causar algumas surpresas desagradáveis, então adicionamos saída de aviso para informá-lo quando isso acontece.

chaves de configuração HTTP_PORTS e HTTPS_PORTS

Aplicativos e contêineres geralmente recebem apenas uma porta para escutar, por exemplo, a porta 80, sem restrições adicionais, como host ou caminho. HTTP_PORTS e HTTPS_PORTS são novas chaves de configuração que permitem especificar as portas de escuta para Kestrel e servidores HTTP.sys e HTTP.sys. Eles podem ser definidos com os prefixos de variável de ambiente DOTNET_ e ASPNETCORE_, ou especificados diretamente por meio de qualquer outra entrada de configuração, como appsettings.json. Cada um é uma lista delimitada por ponto-e-vírgula de valores de porta. Por exemplo:

ASPNETCORE_HTTP_PORTS=80;8080
ASPNETCORE_HTTPS_PORTS=443;8081

Isso é abreviação para o seguinte, que especifica o esquema (HTTP ou HTTPS) e qualquer host ou IP:

ASPNETCORE_URLS=http://*:80/;http://*:8080/;https://*:443/;https://*:8081/

Para obter mais informações, consulte Configurar pontos de extremidade para o servidor Web do ASP.NET CoreKestrel e implementação do servidor Web HTTP.sys no ASP.NET Core.

Nome do host SNI em ITlsHandshakeFeature

O nome do host SNI (Indicação de Nome do Servidor) agora está exposto na propriedade HostName da interface ITlsHandshakeFeature.

O SNI faz parte do processo de handshake do TLS. Ele permite que os clientes especifiquem o nome do host ao qual estão tentando se conectar quando o servidor hospeda vários hosts ou domínios virtuais. Para apresentar o certificado de segurança correto durante o processo de handshake, o servidor precisa saber o nome do host selecionado para cada solicitação.

Normalmente, o nome do host é tratado apenas dentro da pilha TLS e é usado para selecionar o certificado correspondente. Porém, ao expô-lo, outros componentes em um aplicativo podem usar essas informações para fins como diagnóstico, limitação de taxa, roteamento e cobrança.

Expor o nome do host é útil para serviços em grande escala que gerenciam milhares de associações de SNI. Esse recurso pode melhorar significativamente a eficiência de depuração durante escalonamentos de clientes. O aumento da transparência permite uma resolução de problemas mais rápida e maior confiabilidade do serviço.

Para obter mais informações, consulte ITlsHandshakeFeature.HostName.

IHttpSysRequestTimingFeature

IHttpSysRequestTimingFeature fornece informações detalhadas de tempo para solicitações ao usar o servidor HTTP.sys e a hospedagem em processo com o IIS:

IHttpSysRequestTimingFeature.TryGetTimestamp recupera o carimbo de data/hora para o tipo de tempo fornecido:

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys();

var app = builder.Build();

app.Use((context, next) =>
{
    var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();

    var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    var timingType = HttpSysRequestTimingType.RequestRoutingEnd;

    if (feature.TryGetTimestamp(timingType, out var timestamp))
    {
        logger.LogInformation("Timestamp {timingType}: {timestamp}",
                                          timingType, timestamp);
    }
    else
    {
        logger.LogInformation("Timestamp {timingType}: not available for the "
                                           + "current request",    timingType);
    }

    return next(context);
});

app.MapGet("/", () => Results.Ok());

app.Run();

Para obter mais informações, consulte Obter informações de tempo detalhadas com informações de IHttpSysRequestTimingFeature e Timing e hospedagem em processo com o IIS.

HTTP.sys: suporte de aceitação para buffer de resposta no modo kernel

Em alguns cenários, grandes volumes de gravações pequenas com alta latência podem causar um impacto significativo no desempenho de HTTP.sys. Esse impacto ocorre devido à falta de um buffer Pipe na implementação HTTP.sys. Para melhorar o desempenho nesses cenários, o suporte para buffer de resposta foi incluído ao HTTP.sys. Habilite o buffer definindo HttpSysOptions.EnableKernelResponseBuffering como true.

O buffer de resposta deve ser habilitado por um aplicativo que faz E/S síncrona ou E/S assíncrona com não mais de uma gravação pendente por vez. Nesses cenários, o buffer de resposta pode melhorar significativamente a taxa de transferência em relação a conexões de alta latência.

Aplicativos que usam E/S assíncrona e que podem ter mais de uma gravação pendente por vez não devem usar esse sinalizador. Habilitar esse sinalizador pode resultar em maior uso de CPU e memória por HTTP.Sys.

Autenticação e autorização

O ASP.NET Core 8 adiciona novos recursos à autenticação e autorização.

Pontos de extremidade de API Identity

MapIdentityApi<TUser> é um novo método de extensão que adiciona dois pontos de extremidade de API (/register e /login). O objetivo principal do MapIdentityApi é facilitar que os desenvolvedores usem o ASP.NET Core Identity para autenticação em aplicativos ou aplicativos Blazor de página única baseados em JavaScript (SPA). Em vez de usar a interface do usuário padrão fornecida pelo ASP.NET Core Identity, que se baseia em Razor Páginas, MapaIdentity a API adiciona JSpontos de extremidade de API ON mais adequados para aplicativos SPA e aplicativos nonbrowser. Para obter mais informações, consulte Identity pontos de extremidade de API.

IAuthorizationRequirementData

Antes do ASP.NET Core 8, adicionar uma política de autorização parametrizada a um ponto de extremidade exigia a implementação de um:

  • AuthorizeAttribute para cada política.
  • AuthorizationPolicyProvider para processar uma política personalizada de um contrato baseado em cadeia de caracteres.
  • AuthorizationRequirement para a política.
  • AuthorizationHandler para cada requisito.

Por exemplo, considere o exemplo a seguir escrito para ASP.NET Core 7.0:

using AuthRequirementsData.Authorization;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder();

builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();
builder.Services.AddControllers();
builder.Services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeAuthorizationHandler>();

var app = builder.Build();

app.MapControllers();

app.Run();
using Microsoft.AspNetCore.Mvc;

namespace AuthRequirementsData.Controllers;

[ApiController]
[Route("api/[controller]")]
public class GreetingsController : Controller
{
    [MinimumAgeAuthorize(16)]
    [HttpGet("hello")]
    public string Hello() => $"Hello {(HttpContext.User.Identity?.Name ?? "world")}!";
}
using Microsoft.AspNetCore.Authorization;
using System.Globalization;
using System.Security.Claims;

namespace AuthRequirementsData.Authorization;

class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeRequirement>
{
    private readonly ILogger<MinimumAgeAuthorizationHandler> _logger;

    public MinimumAgeAuthorizationHandler(ILogger<MinimumAgeAuthorizationHandler> logger)
    {
        _logger = logger;
    }

    // Check whether a given MinimumAgeRequirement is satisfied or not for a particular
    // context.
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                               MinimumAgeRequirement requirement)
    {
        // Log as a warning so that it's very clear in sample output which authorization
        // policies(and requirements/handlers) are in use.
        _logger.LogWarning("Evaluating authorization requirement for age >= {age}",
                                                                    requirement.Age);

        // Check the user's age
        var dateOfBirthClaim = context.User.FindFirst(c => c.Type ==
                                                                 ClaimTypes.DateOfBirth);
        if (dateOfBirthClaim != null)
        {
            // If the user has a date of birth claim, check their age
            var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value, CultureInfo.InvariantCulture);
            var age = DateTime.Now.Year - dateOfBirth.Year;
            if (dateOfBirth > DateTime.Now.AddYears(-age))
            {
                // Adjust age if the user hasn't had a birthday yet this year.
                age--;
            }

            // If the user meets the age criterion, mark the authorization requirement
            // succeeded.
            if (age >= requirement.Age)
            {
                _logger.LogInformation("Minimum age authorization requirement {age} satisfied",
                                         requirement.Age);
                context.Succeed(requirement);
            }
            else
            {
                _logger.LogInformation("Current user's DateOfBirth claim ({dateOfBirth})" +
                    " does not satisfy the minimum age authorization requirement {age}",
                    dateOfBirthClaim.Value,
                    requirement.Age);
            }
        }
        else
        {
            _logger.LogInformation("No DateOfBirth claim present");
        }

        return Task.CompletedTask;
    }
}

O código de exemplo completo está aqui no repositório AspNetCore.Docs.Samples.

ASP.NET Core 8 apresenta a interface IAuthorizationRequirementData. O IAuthorizationRequirementData usa a permite que a definição de atributo especifique os requisitos associados à política de autorização. Usando IAuthorizationRequirementData, o código de política de autorização personalizado anterior pode ser escrito com menos linhas de código. O arquivo atualizado Program.cs:

  using AuthRequirementsData.Authorization;
  using Microsoft.AspNetCore.Authorization;
  
  var builder = WebApplication.CreateBuilder();
  
  builder.Services.AddAuthentication().AddJwtBearer();
  builder.Services.AddAuthorization();
  builder.Services.AddControllers();
- builder.Services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();
  builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeAuthorizationHandler>();
  
  var app = builder.Build();
  
  app.MapControllers();
  
  app.Run();

O MinimumAgeAuthorizationHandler atualizado:

using Microsoft.AspNetCore.Authorization;
using System.Globalization;
using System.Security.Claims;

namespace AuthRequirementsData.Authorization;

- class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeRequirement>
+ class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeAuthorizeAttribute>
{
    private readonly ILogger<MinimumAgeAuthorizationHandler> _logger;

    public MinimumAgeAuthorizationHandler(ILogger<MinimumAgeAuthorizationHandler> logger)
    {
        _logger = logger;
    }

    // Check whether a given MinimumAgeRequirement is satisfied or not for a particular
    // context
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
-                                              MinimumAgeRequirement requirement)
+                                              MinimumAgeAuthorizeAttribute requirement)
    {
        // Remaining code omitted for brevity.

O exemplo atualizado completo pode ser encontrado aqui.

Consulte políticas de autorização personalizadas com IAuthorizationRequirementData para obter um exame detalhado do novo exemplo.

Proteger pontos de extremidade da interface do usuário do Swagger

Os pontos de extremidade da interface do usuário do Swagger agora podem ser protegidos nos ambientes de produção chamando MapSwagger().RequireAuthorization. Para obter mais informações, consulte Pontos de extremidade da interface do usuário do Swagger

Diversos

As seções a seguir descrevem novos recursos diversos no ASP.NET Core 8.

Suporte a serviços com chave na Injeção de Dependência

Os serviços com chave referem-se a um mecanismo para registrar e recuperar serviços de Injeção de Dependência (DI) por meio de chaves. Um serviço é associado a uma chave chamando AddKeyedSingleton (ou AddKeyedScoped ou AddKeyedTransient) para registrá-la. Acesse um serviço registrado especificando a chave com o atributo [FromKeyedServices]. O código a seguir mostra como usar serviços com chave:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
builder.Services.AddControllers();

var app = builder.Build();

app.MapGet("/big", ([FromKeyedServices("big")] ICache bigCache) => bigCache.Get("date"));
app.MapGet("/small", ([FromKeyedServices("small")] ICache smallCache) =>
                                                               smallCache.Get("date"));

app.MapControllers();

app.Run();

public interface ICache
{
    object Get(string key);
}
public class BigCache : ICache
{
    public object Get(string key) => $"Resolving {key} from big cache.";
}

public class SmallCache : ICache
{
    public object Get(string key) => $"Resolving {key} from small cache.";
}

[ApiController]
[Route("/cache")]
public class CustomServicesApiController : Controller
{
    [HttpGet("big-cache")]
    public ActionResult<object> GetOk([FromKeyedServices("big")] ICache cache)
    {
        return cache.Get("data-mvc");
    }
}

public class MyHub : Hub
{
    public void Method([FromKeyedServices("small")] ICache cache)
    {
        Console.WriteLine(cache.Get("signalr"));
    }
}

Modelos de projeto do Visual Studio para aplicativos SPA com back-end do ASP.NET Core

Os modelos de projeto do Visual Studio agora são a maneira recomendada de criar aplicativos de página única (SPAs) que têm um back-end do ASP.NET Core. São fornecidos modelos que criam aplicativos com base nas estruturas JavaScript Angular, React e Vue. Estes modelos:

  • Criam uma solução do Visual Studio com um projeto de front-end e um projeto de back-end.
  • Usam o tipo de projeto do Visual Studio para JavaScript e TypeScript (.esproj) para o front-end.
  • Usam um projeto ASP.NET Core para o back-end.

Para obter mais informações sobre os modelos do Visual Studio e como acessar os modelos herdados, confira Visão geral dos aplicativos de página única (SPAs) no ASP.NET Core

Suporte para atributos genéricos

Atributos que antes exigiam um parâmetro Type agora estão disponíveis em variantes genéricas mais limpas. Isso é possível pelo suporte para atributos genéricos no C# 11. Por exemplo, a sintaxe para anotar o tipo de resposta de uma ação pode ser modificada da seguinte maneira:

[ApiController]
[Route("api/[controller]")]
public class TodosController : Controller
{
  [HttpGet("/")]
- [ProducesResponseType(typeof(Todo), StatusCodes.Status200OK)]
+ [ProducesResponseType<Todo>(StatusCodes.Status200OK)]
  public Todo Get() => new Todo(1, "Write a sample", DateTime.Now, false);
}

Variantes genéricas tem suporte para os seguintes atributos:

  • [ProducesResponseType<T>]
  • [Produces<T>]
  • [MiddlewareFilter<T>]
  • [ModelBinder<T>]
  • [ModelMetadataType<T>]
  • [ServiceFilter<T>]
  • [TypeFilter<T>]

Análise de código em aplicativos ASP.NET Core

Os novos analisadores mostrados na tabela a seguir estão disponíveis no ASP.NET Core 8.0.

ID do diagnóstico Interruptiva ou não interruptiva Descrição
ASP0016 Não interruptiva Não retorne um valor de RequestDelegate
ASP0019 Não interruptiva Sugerir o uso de IHeaderDictionary.Append ou do indexador
ASP0020 Não interruptiva Tipos complexos referenciados por parâmetros de rota devem ser analisáveis
ASP0021 Não interruptiva O tipo de retorno do método BindAsync deve ser ValueTask<T>
ASP0022 Não interruptiva Conflito de rota detectado entre manipuladores de rota
ASP0023 Não interruptiva MVC: conflito de rota detectado entre manipuladores de rota
ASP0024 Não interruptiva O manipulador de rotas tem vários parâmetros com o atributo [FromBody]
ASP0025 Não interruptiva Usar AddAuthorizationBuilder

Ferramentas de rota

ASP.NET Core é baseado no roteamento. APIs mínimas, APIs Web, Razor Pages e Blazor usam rotas para personalizar como as solicitações HTTP são mapeadas para o código.

No .NET 8, investimos em um conjunto de novos recursos para tornar o roteamento mais fácil de aprender e usar. Outros novos recursos incluem:

Para obter mais informações, consulte Ferramentas de rota no .NET 8.

Métricas do ASP.NET Core

As métricas são medidas relatadas ao longo do tempo e geralmente são usadas para monitorar a integridade de um aplicativo e gerar alertas. Por exemplo, um contador que relata solicitações HTTP com falha pode ser exibido em painéis ou gerar alertas quando falhas passam um limite.

Esta visualização adiciona novas métricas em todo o ASP.NET Core usando System.Diagnostics.Metrics. Metrics é uma API moderna para relatórios e coleta de informações sobre aplicativos.

As métricas oferecem muitas melhorias em comparação com os contadores de eventos existentes:

  • Novos tipos de medidas com contadores, medidores e histogramas.
  • Relatórios avançados com valores multidimensionais.
  • Integração ao ecossistema nativo de nuvem mais amplo alinhando-se aos padrões openTelemetry.

As métricas foram adicionadas para hospedagem ASP.NET Core Kestrel e SignalR. Para obter mais informações, consulte System.Diagnostics.Metrics.

IExceptionHandler

IExceptionHandler é uma nova interface que dá ao desenvolvedor um retorno de chamada para lidar com exceções conhecidas em um local central.

as implementações IExceptionHandler são registradas por meio da chamada IServiceCollection.AddExceptionHandler<T>. Várias implementações podem ser adicionadas e são chamadas na ordem registrada. Se um manipulador de exceção tratar uma solicitação, ele poderá retornar true para interromper o processamento. Se uma exceção não for tratada por nenhum manipulador de exceção, o controle retornará ao comportamento padrão e às opções do middleware.

Para obter mais informações, consulte IExceptionHandler.

Melhor experiência de depuração

Atributos de personalização de depuração foram adicionados a tipos como HttpContext, HttpRequest, HttpResponse, ClaimsPrincipal e WebApplication. As exibições avançadas do depurador para esses tipos facilitam a localização de informações importantes no depurador do IDE. As capturas de tela a seguir mostram a diferença que esses atributos fazem na exibição do depurador do HttpContext.

.NET 7:

Exibição inútil do depurador do tipo HttpContext no .NET 7.

.NET 8:

Exibição útil do depurador do tipo HttpContext no .NET 8.

A exibição do depurador para WebApplication realça informações importantes, como pontos de extremidade, middleware e valores IConfiguration configurados.

.NET 7:

Exibição inútil do depurador do tipo WebApplication no .NET 7.

.NET 8:

Exibição útil do depurador do tipo WebApplication no .NET 8.

Para obter mais informações sobre melhorias de depuração no .NET 8, consulte:

IPNetwork.Parse e TryParse

O novo Parse e os métodos TryParse na adição de suporte IPNetwork para a criação de um IPNetwork usando uma cadeia de caracteres de entrada na notação CIDR ou "notação de barra".

Aqui estão exemplos de IPv4:

// Using Parse
var network = IPNetwork.Parse("192.168.0.1/32");
// Using TryParse
bool success = IPNetwork.TryParse("192.168.0.1/32", out var network);
// Constructor equivalent
var network = new IPNetwork(IPAddress.Parse("192.168.0.1"), 32);

E aqui estão exemplos para IPv6:

// Using Parse
var network = IPNetwork.Parse("2001:db8:3c4d::1/128");
// Using TryParse
bool success = IPNetwork.TryParse("2001:db8:3c4d::1/128", out var network);
// Constructor equivalent
var network = new IPNetwork(IPAddress.Parse("2001:db8:3c4d::1"), 128);

Cache de saída baseado em Redis

O ASP.NET Core 8 adiciona suporte para usar o Redis como um cache distribuído para cache de saída. O cache de saída é um recurso que permite que um aplicativo armazene em cache a saída de um ponto de extremidade de API mínimo, ação do controlador ou página Razor. Para obter mais informações, confira Cache de Saída.

Middleware de curto-circuito após o roteamento

Ao fazer o roteamento corresponder a um ponto de extremidade, ele normalmente permite que o restante do pipeline de middleware seja executado antes de invocar a lógica do ponto de extremidade. Os serviços podem reduzir o uso de recursos filtrando solicitações conhecidas no início do pipeline. Use o método de extensão ShortCircuit para fazer com que o roteamento invoque a lógica do ponto de extremidade imediatamente e, em seguida, encerre a solicitação. Por exemplo, uma determinada rota pode não precisar passar pela autenticação ou middleware CORS. O exemplo a seguir solicitações de curto-circuito que correspondem à rota /short-circuit:

app.MapGet("/short-circuit", () => "Short circuiting!").ShortCircuit();

Use o método MapShortCircuit para configurar o curto-circuito para várias rotas ao mesmo tempo, passando para ele uma matriz de parâmetros de prefixos de URL. Por exemplo, navegadores e bots geralmente investigam servidores para caminhos conhecidos como robots.txt e favicon.ico. Se o aplicativo não tiver esses arquivos, uma linha de código poderá configurar as rotas:

app.MapShortCircuit(404, "robots.txt", "favicon.ico");

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

Extensibilidade do middleware de log HTTP

O middleware de log HTTP tem vários novos recursos:

  • HttpLoggingFields.Duration: quando habilitado, o middleware emite um novo log no final da solicitação e resposta que mede o tempo total necessário para o processamento. Este novo campo foi adicionado ao conjunto HttpLoggingFields.All.
  • HttpLoggingOptions.CombineLogs: quando habilitado, o middleware consolida todos os logs habilitados para uma solicitação e resposta em um log no final. Uma única mensagem de log inclui a solicitação, o corpo da solicitação, a resposta, o corpo da resposta e a duração.
  • IHttpLoggingInterceptor: uma nova interface para um serviço que pode ser implementado e registrado (usando AddHttpLoggingInterceptor) para receber retornos de chamada por solicitação e por resposta para personalizar quais detalhes são registrados. As configurações de log específicas do ponto de extremidade são aplicadas primeiro e podem ser substituídas nesses retornos de chamada. Uma implementação pode:
    • Inspecione uma solicitação e uma resposta.
    • Habilite ou desabilite qualquer HttpLoggingFields.
    • Ajuste a quantidade de logs do corpo de solicitação ou resposta.
    • Adicione campos personalizados aos logs.

Para obter mais informações, consulte o log HTTP no .NET Core e no ASP.NET Core.

Novas APIs no ProblemDetails para dar suporte a integrações mais resilientes

No .NET 7, o serviço ProblemDetails foi introduzido para melhorar a experiência de geração de respostas de erro que estão em conformidade com a especificação ProblemDetails. No .NET 8, uma nova API foi adicionada para facilitar a implementação do comportamento de fallback se IProblemDetailsService não for possível gerar ProblemDetails. O seguinte exemplo ilustra o uso da nova API TryWriteAsync:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/exception", () =>
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Para obter mais informações, consulte o fallback IProblemDetailsService

Recursos adicionais