Partilhar via


O que há de novo no ASP.NET Core no .NET 8

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

Blazor

Interface de utilizador web de pilha completa

Com o lançamento do .NET 8, o Blazor é uma estrutura full stack de interface do usuário para a web, ideal para o desenvolvimento de aplicativos que processam conteúdo ao nível do componente ou da página com:

  • Renderização estática em servidor (também chamada renderização estática em 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 interativo) para gerar componentes interativos com pré-renderização no servidor.
  • Renderização interativa de WebAssembly (também conhecida como renderização do lado do cliente, CSR, considerada sempre interativa) para gerar componentes interativos no cliente com pré-renderização no servidor.
  • Renderização Interativa Automática para usar inicialmente o tempo de execução do ASP.NET Core no lado do servidor para renderização e interatividade de conteúdo. O tempo de execução do .NET WebAssembly no cliente é usado para renderização e interatividade subsequentes depois que o pacote de Blazor é baixado e o tempo de execução do WebAssembly é ativado. A renderização automática interativa geralmente fornece a experiência de inicialização de aplicativo mais rápida.

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

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

Os exemplos ao longo da documentação Blazor foram atualizados para uso em Blazor Web Apps. Os exemplos Blazor Server ainda permanecem em versões de conteúdo para .NET 7 ou anterior.

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

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

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

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 aplicativos Blazor nas principais versões e como resolver problemas de cache HTTP.

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

Novo modelo de Blazor Web App

Introduzimos um novo modelo de projeto Blazor: o modelo Blazor Web App. O novo modelo fornece um único ponto de partida para usar componentes Blazor para criar qualquer estilo de interface do usuário da Web. O modelo combina os pontos fortes dos modelos de hospedagem de Blazor Server e Blazor WebAssembly existentes com os novos recursos de Blazor adicionados no .NET 8: renderização estática do lado do servidor (SSR estático), renderização de streaming, navegação aprimorada e manipulação de formulários e a 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 ASP.NET Core Hosted foi removida do modelo Blazor WebAssembly. Ambos os cenários são representados por opções ao usar o modelo Blazor Web App.

Note

Os aplicativos Blazor Server e Blazor WebAssembly existentes permanecem com suporte no .NET 8. Opcionalmente, estas aplicações podem ser atualizadas para usar os novos recursos integrais da interface web do utilizador Blazor.

Para obter mais informações sobre o novo modelo de Blazor Web App, consulte os seguintes artigos:

Novos inicializadores de JS para Blazor Web Apps

Para as aplicações Blazor Server, Blazor WebAssemblye Blazor Hybrid:

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

Os inicializadores de JS herdados anteriores não são invocados por padrão em um Blazor Web App. Para Blazor Web Apps, um novo conjunto de inicializadores de JS são usados: beforeWebStart, afterWebStarted, beforeServerStart, afterServerStarted, beforeWebAssemblyStarte afterWebAssemblyStarted.

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

Divisão das diretrizes de pré-renderização e integração

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

Persistir o estado do componente num Blazor Web App

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

Blazor Web Apps persistem automaticamente qualquer estado registrado no nível do aplicativo criado durante a pré-renderização, removendo a necessidade do Persist Component State Tag Helper.

Tratamento de formulários e vinculação de modelos

Blazor componentes agora podem lidar com solicitações de formulário enviadas, incluindo vinculação de modelo e validação dos dados da solicitação. Os componentes podem implementar formulários com manipuladores de formulário separados usando a marca HTML <form> padrão ou usando o componente EditForm existente.

A associação do modelo de formulário no Blazor respeita os atributos do contrato de dados (por exemplo, [DataMember] e [IgnoreDataMember]) para personalizar a forma como os dados do formulário são associados ao modelo.

Novo suporte 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 antifalsificação. Se uma verificação antifalsificação falhar, uma resposta 400 (Solicitação incorreta) será retornada sem processamento de formulário. Os novos recursos antifalsificação são habilitados 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 visão geral dos formulários do ASP.NET Core Blazor.

Navegação e manipulação de formulários aprimoradas

A renderização estática do lado do servidor (SSR estático) normalmente executa uma atualização de página inteira 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 de página e o tratamento de formulários intercetando a solicitação e executando uma solicitação de busca. Blazor em seguida, lida com o conteúdo de resposta renderizado corrigindo-o no DOM do navegador. A navegação aprimorada e o tratamento de formulários evitam a necessidade de uma atualização de página inteira e preservam mais do estado da página, para que as páginas sejam carregadas mais rapidamente e sem problemas. A navegação avançada é ativada por padrão quando o script Blazor (blazor.web.js) é carregado. A manipulação aprimorada de formulários pode ser habilitada 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, consulte as seguintes orientações:

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

Algumas aplicações dependem da interoperabilidade de JS para realizar tarefas de inicialização específicas de cada página. Ao utilizar a funcionalidade de navegação avançada do Blazorcom páginas renderizadas estaticamente que realizam tarefas de inicialização de interoperabilidade JS, as funções JS específicas da página podem não ser executadas novamente como esperado cada vez que ocorre uma navegação melhorada na página. Um novo artigo explica como lidar com esse cenário em Blazor Web Apps:

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

Renderização em streaming

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

Por exemplo, para renderizar uma página, talvez seja necessário fazer uma consulta de banco de dados de longa duração 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 de streaming inicialmente renderiza toda a página com conteúdo de marcador de posição enquanto operações assíncronas são executadas. Após a conclusão das operações assíncronas, o conteúdo atualizado é enviado para o cliente na mesma conexão de resposta e integrado no DOM. O benefício 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 obter mais informações, consulte Razordo ASP.NET Core .

Injetar serviços chaveados em componentes

Blazor agora oferece suporte à injeção de serviços com chave usando o atributo [Inject]. As chaves permitem definir o âmbito para o registo e o consumo de serviços ao usar a injeção de dependência. Use a nova propriedade InjectAttribute.Key para especificar a chave que o serviço deve injetar:

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

A diretiva @injectRazor não suporta serviços com chave para esta versão, mas o trabalho é rastreado pelo Update @inject para oferecer suporte a serviços com chave (dotnet/razor #9286) para uma versão futura do .NET.

Para obter mais informações, consulte ASP.NET Core Blazor de injeção de dependência.

Aceder a HttpContext como 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; }

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

Para obter um exemplo que passe o estado HttpContext, com acesso e atualização de tokens para componentes, consulte o ASP.NET Core no lado do servidor e os cenários de segurança adicionais e Blazor Web App.

Renderizar Razor componentes fora do ASP.NET Core

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

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

Suporte de seções

Os novos componentes SectionOutlet e SectionContent em Blazor adicionam suporte para a especificação de pontos de saída para conteúdo que pode ser preenchido posteriormente. As seções geralmente são 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 as seções ASP.NET Core Blazor.

Suporte para páginas de erro

Blazor Web Apps pode definir uma página de erro personalizada para uso com o middleware de tratamento de exceções ASP.NET Core. O Blazor Web App modelo de projeto inclui uma página de erro padrão com conteúdo semelhante ao usado nos aplicativos MVC e Razor Pages. Quando a página de erro é processada em resposta a uma solicitação do Exception Handling Middleware, a página de erro sempre é renderizada como um componente de servidor estático, mesmo que a interatividade esteja habilitada de outra forma.

Consulte o componente Error (Components/Pages/Error.razor) do projeto do servidor no modelo de projeto Blazor Web App (repositório dotnet/aspnetcore GitHub).

Note

Os links de documentação para a fonte de referência do .NET geralmente carregam a ramificação padrão do repositório, que representa o desenvolvimento atual para a próxima versão do .NET. Para selecionar uma tag para uma versão específica, use a lista suspensa Alternar entre ramificações ou tags. Para obter mais informações, consulte Como selecionar uma marca de versão do código-fonte ASP.NET Core (dotnet/AspNetCore.Docs #26205).

QuickGrid

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

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

Para obter mais informações, consulte ASP.NET componente Core Blazor 'QuickGrid'.

Rota para elementos nomeados

Blazor agora oferece suporte ao 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 id padrão, Blazor rolará corretamente para esse elemento quando o fragmento de URL corresponder ao identificador do elemento.

Para mais informações, consulte ASP.NET Core Blazor navegação.

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, consulte os seguintes recursos:

Virtualizar conteúdo vazio

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

Para obter mais informações, consulte ASP.NET Core Razor component virtualization.

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

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

Monitore 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 no CircuitHandler. A atividade de circuito de entrada é qualquer atividade enviada do navegador para o servidor, como eventos da interface de utilizador ou chamadas de interoperabilidade entre JavaScript e .NET.

Para obter mais informações, consulte ASP.NET Core BlazorSignalR guidance.

Desempenho de tempo de execução mais rápido com o Jiterpreter

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

Para obter mais informações, consulte ASP.NET Core Blazor WebAssembly ferramentas de construção e compilação antecipada (AOT).

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

Blazor WebAssembly compilação antecipada (AOT) agora usa SIMD de largura fixa do WebAssembly e tratamento de exceção do WebAssembly por padrão para melhorar o desempenho do tempo de execução.

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

Embalagem Webcil otimizada para a Web

O Webcil é um pacote amigável para a Web de assemblies .NET que remove 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 Blazor WebAssembly aplicativos.

Para obter mais informações, consulte Host e implantar ASP.NET Core Blazor WebAssembly.

Note

Antes do lançamento do .NET 8, as diretrizes na configuração de implantação para aplicativos Blazor WebAssembly hospedados em ASP.NET Core tratam de ambientes que impedem os clientes de baixar e executar DLLs com uma abordagem de agregação de várias partes. No .NET 8 ou posterior, Blazor usa o formato de arquivo Webcil para resolver esse problema. O agrupamento multipartes usando o pacote NuGet experimental descrito no artigo sobre o layout de implantação do WebAssembly não é suportado para apps no .NET 8 ou versões posteriores. Para obter mais informações, consulte Aperfeiçoar Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle pacote para definir um formato personalizado de pacote (dotnet/aspnetcore #36978). Se desejar continuar a usar o pacote de agrupamento de várias partes em aplicações .NET 8 ou posteriores, pode seguir as orientações no artigo para criar o seu próprio pacote NuGet de agrupamento de várias partes, mas não terá suporte da Microsoft.

Blazor WebAssembly melhorias na depuração

Ao depurar .NET no WebAssembly, o depurador agora baixa dados de símbolos a partir das localizações de símbolos configuradas nas preferências do Visual Studio. Isso melhora a experiência de depuração para aplicativos que usam pacotes NuGet.

Agora você pode depurar aplicativos Blazor WebAssembly usando o Firefox. A depuração de aplicativos Blazor WebAssembly requer configurar o navegador para depuração remota e, em seguida, conectar-se ao navegador usando as ferramentas de desenvolvedor do navegador por meio do proxy de depuração .NET WebAssembly. Não é possível depurar o Firefox a partir do Visual Studio neste momento.

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

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

Blazor WebAssembly já não requer habilitar a fonte de script unsafe-eval ao especificar uma Política de Segurança de Conteúdo (CSP).

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

Lidar com exceções detetadas fora do ciclo de vida de um componente Razor

Use ComponentBase.DispatchExceptionAsync em um componente Razor para processar exceções lançadas 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 do 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, consulte Tratar erros em aplicações do ASP.NET Core Blazor.

Configurar o tempo de execução do .NET WebAssembly

O ambiente de execução do .NET WebAssembly agora pode ser configurado para inicialização Blazor.

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

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

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

Para obter mais informações, consulte o seguinte:

Modelos de projeto removem Open Iconic

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

Suporte para cancelar e fechar eventos de caixa de diálogo

Blazor agora suporta os eventos cancel e close no elemento HTML dialog.

No exemplo a seguir:

  • OnClose é chamado quando o diálogo my-dialog é fechado com o botão Fechar.
  • OnCancel é chamado quando o diálogo é cancelado com a tecla Esc. Quando uma caixa de diálogo HTML é descartada com a tecla Esc, os eventos cancel e close são acionados.
<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, ";
}

Blazor Identity Interface do usuário

Blazor suporta a criação de uma UI completa baseada em Blazor-Identity ao escolher a opção de autenticação de Contas Individuais. Você pode selecionar a opção "Contas Individuais" na caixa de diálogo de novo projeto para Blazor Web Apps no Visual Studio ou passar a opção -au|--auth definida como Individual na linha de comando ao criar um novo projeto.

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

Proteja Blazor WebAssembly com o 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 Blazor WebAssembly autônomo com ASP.NET Core Identity.

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

Blazor Server com roteamento Yarp

O roteamento e as ligações profundas para Blazor Server com Yarp funcionam corretamente no .NET 8.

Para obter mais informações, consulte Migrar do ASP.NET Core no .NET 7 para o .NET 8.

Vários Blazor Web Apps por projeto de servidor

O suporte para múltiplos Blazor Web Apps em cada projeto de servidor está a ser considerado para uma futura versão do .NET.

Para obter mais informações, consulte Suporte para várias aplicações Web Blazor por cada projeto de servidor (dotnet/aspnetcore #52216).

Blazor Hybrid

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

[Parameter] atributo não é mais necessário quando fornecido a partir 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 de Keep-Alive

ServerTimeout (padrão: 30 segundos) e KeepAliveInterval (padrão: 15 segundos) podem ser definidos diretamente no 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 .NET 7 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 .NET 8 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 .NET 7 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 do 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 .NET 8 ou posterior para Blazor Web Apps e Blazor Server.

Blazor Web App:

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

Blazor Server:

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

Abordagem anterior para clientes .NET

O exemplo a seguir mostra a atribuição de valores que são o dobro dos valores padrão no .NET 7 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 .NET 8 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

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

A reconexão com estado alcança isso ao:

  • Armazenamento temporário de dados em buffer no servidor e no cliente.
  • Confirmação de mensagens recebidas (ACK-ing) pelo servidor e pelo cliente.
  • Reconhecer quando uma conexão está retornando e reproduzir mensagens que podem ter sido enviadas enquanto a conexão estava inativa.

A reconexão preservando o estado está disponível no .NET 8 ou posterior.

Opte pela reconexão com monitoração de estado no ponto de extremidade do hub do servidor e no cliente:

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

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

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

    As opções StatefulReconnectBufferSize definidas 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 ativar 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 obter mais informações, consulte Configurar a reconexão com monitoração de estado.

APIs mínimas

Esta secção descreve novas funcionalidades para APIs Mínimas. Consulte também a secção sobre AOT Nativo para mais informações relevantes para APIs Mínimas.

Cultura de prevalência do utilizador

A partir do .NET 8, a propriedade RequestLocalizationOptions.CultureInfoUseUserOverride permite que o aplicativo decida se deseja ou não usar configurações não padrão do Windows para as CultureInfoDateTimeFormat propriedades e NumberFormat . Isso não tem impacto no Linux. Isso corresponde diretamente a UseUserOverride.

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

Vinculação a formulários

A associação explícita a valores de formulário usando o atributo [FromForm] agora é suportada. Os parâmetros vinculados à solicitação com [FromForm] incluem um token antifalsificação . O token antifalsificação é validado quando a solicitação é processada.

A vinculação inferida a formulários usando os tipos IFormCollection, IFormFilee IFormFileCollection também é suportada. Os metadados do OpenAPI são inferidos para parâmetros de formulário para dar suporte à integração com o Swagger UI.

Para mais informações, consulte:

A vinculação de formulários agora é suportada para:

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

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

Antifalsificação com APIs mínimas

Esta versão adiciona um middleware para validar tokens antifalsificação, usados para mitigar ataques de falsificação de pedidos entre sites. Ligue para AddAntiforgery para registrar serviços antifalsificação na DI. WebApplicationBuilder adiciona automaticamente o middleware quando os serviços antifalsificação são registrados no contêiner DI. Os tokens anti-falsificação são usados para mitigar 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ó é validado se:

  • O ponto de extremidade contém metadados que implementam IAntiforgeryMetadata, onde RequiresValidation=true.
  • O método HTTP relevante associado ao endpoint é um método HTTP . Os métodos relevantes são todos os 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 with Minimal APIs.

Interface nova IResettable em ObjectPool

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

Nesta versão, tornamos o pool de objetos mais fácil de usar adicionando a interface IResettable. Os tipos reutilizáveis geralmente precisam ser redefinidos para um estado padrão entre os usos. Os tipos IResettable são automaticamente redefinidos quando devolvidos a uma pool de objetos.

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

AOT nativo

Foi adicionado suporte nativo do .NET para ahead-of-time (AOT). Os aplicativos que são publicados usando AOT podem ter um desempenho substancialmente melhor: tamanho menor do aplicativo, menor uso de memória e tempo de inicialização mais rápido. O AOT nativo é atualmente suportado por gRPC, Minimal API e aplicações de serviço ao trabalhador. Para obter mais informações, consulte Suporte do ASP.NET Core para AOT Nativo e Tutorial: Publicar uma aplicação ASP.NET Core usando AOT Nativo. Para obter informações sobre problemas conhecidos com a compatibilidade do ASP.NET Core e do AOT nativo, veja a questão no GitHub dotnet/core #8288.

Bibliotecas e AOT nativo

Muitas das bibliotecas populares usadas em projetos ASP.NET Core atualmente têm alguns problemas de compatibilidade quando usadas em um projeto direcionado à AOT nativa, como:

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

As bibliotecas que usam esses recursos dinâmicos precisam ser atualizadas para trabalhar com AOT nativo. Eles podem ser atualizados usando ferramentas como geradores de fontes Roslyn.

Os autores de bibliotecas que desejam apoiar o AOT nativo são encorajados a:

Novo modelo de projeto

O novo modelo de projeto ASP.NET Core Web API (Native AOT) (nome abreviado ) cria um projeto com a publicação AOT habilitada. Para obter mais informações, consulte o modelo de API da Web (AOT nativo).

Novo método CreateSlimBuilder

O método CreateSlimBuilder() usado no modelo Web API (Native AOT) inicializa o WebApplicationBuilder com o mínimo de recursos 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 do arquivo JSON para appsettings.json e appsettings.{EnvironmentName}.json.
  • Configuração de segredos do usuário.
  • Registo de consola.
  • Configuração de registo.

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

Novo método CreateEmptyBuilder

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

Aqui está um exemplo de como usar essa API para criar um pequeno aplicativo Web:

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 AOT nativo usando o .NET 8 Preview 7 em uma máquina linux-x64 resulta em um executável nativo autônomo de cerca de 8,5 MB.

Tamanho reduzido do aplicativo com suporte a HTTPS configurável

Reduzimos ainda mais o tamanho 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 que são 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.

Serialização JSON de tipos de IAsyncEnumerable<T> gerados pelo compilador

Novos recursos foram adicionados ao System.Text.Json para oferecer melhor suporte ao AOT nativo. Essas novas funcionalidades adicionam capacidades ao modo de geração de código-fonte do System.Text.Json, porque a reflexão não é suportada pela AOT.

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

Essa API é útil em cenários em que um manipulador de rotas usa yield return para retornar uma enumeração de forma assíncrona. Por exemplo, para materializar linhas de uma consulta de banco de dados. Para obter mais informações, consulte suporte a tipos indescritíveis no anúncio do .NET 8 Preview 4.

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

APIs de nível superior anotadas para avisos de corte

Agora, os principais pontos de entrada para subsistemas que não funcionam de maneira confiável com AOT nativo são anotados. Quando esses métodos são chamados de um aplicativo com AOT nativo habilitado, um aviso é fornecido. Por exemplo, o código a seguir produz um aviso na invocação de AddControllers porque essa API não é compatível com trim e não é suportada pela Native AOT.

janela do Visual Studio mostrando a mensagem de aviso IL2026 no método AddControllers que diz que o MVC não oferece suporte a AOT nativo no momento.

Solicitar gerador de delegados

Para tornar as APIs mínimas compatíveis com o AOT nativo, estamos introduzindo o Request Delegate Generator (RDG). O RDG é um gerador de fonte que faz o que o RequestDelegateFactory (RDF) faz. Ou seja, ele transforma os vários MapGet(), MapPost() e outras chamadas semelhantes em instâncias RequestDelegate associadas às rotas especificadas. Mas em vez de fazê-lo na memória em um aplicativo quando ele é iniciado, o RDG faz isso em tempo de compilação e gera código C# diretamente no projeto. O RDG:

  • Remove a geração em tempo de execução deste código.
  • Garante que os tipos usados em APIs sejam analisáveis estaticamente pela cadeia de ferramentas AOT nativa.
  • Garanta que o código necessário não seja removido.

Estamos trabalhando para garantir que o maior número possível de recursos mínimos da API sejam suportados pelo RDG e, portanto, compatíveis com a AOT nativa.

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

Melhor desempenho usando intercetores

O Gerador de Delegados de Pedidos utiliza a nova funcionalidade do compilador de interceptores C# 12 para suportar a interceção de chamadas para os métodos Minimal API Map com variantes geradas de forma estática em tempo de execução. O uso de intercetadores resulta em maior desempenho de inicialização para aplicativos compilados com PublishAot.

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

APIs mínimas geradas em tempo de execução suportam o registo de logs automaticamente (ou lançamento de exceções nos ambientes Development) quando a ligação de parâmetros falha. O .NET 8 introduz o mesmo suporte para APIs geradas em tempo de compilação por meio do Request Delegate Generator (RDG). Para mais informações, consulte Registo e tratamento de exceções em APIs Mínimas geradas em tempo de compilação.

AOT e System.Text.Json

APIs mínimas são otimizadas para receber e retornar cargas úteis JSON usando System.Text.Json, portanto, os requisitos de compatibilidade para JSON e AOT nativo também se aplicam. A compatibilidade AOT nativa requer o uso do gerador de código-fonte System.Text.Json. Todos os tipos aceitos como parâmetros ou retornados de delegados 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 ASP.NET Core atualmente têm alguns problemas de compatibilidade se usadas em um projeto direcionado à AOT nativa. As bibliotecas populares geralmente dependem dos recursos dinâmicos do .NET reflection para inspecionar e descobrir tipos, carregar condicionalmente bibliotecas em tempo de execução e gerar código rapidamente para implementar sua funcionalidade. Essas bibliotecas precisam ser atualizadas para trabalhar com AOT nativo usando ferramentas como geradores de código-fonte Roslyn.

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

Servidores Kestrel e HTTP.sys

Existem várias novas funcionalidades para Kestrel e HTTP.sys.

Suporte para pipes nomeados no Kestrel

Named pipes é uma tecnologia popular para estabelecer comunicação entre processos (IPC) entre aplicações Windows. Agora pode criar um servidor IPC usando .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 o .NET e o gRPC para criar um servidor e um cliente IPC, consulte Comunicação entre processos com o gRPC.

Melhorias de desempenho no transporte de tubos nomeados

Melhorámos o desempenho da ligação do tubo nomeado. O transporte por pipe nomeado do Kestrelagora aceita conexões simultâneas e reutiliza instâncias de NamedPipeServerStream.

Tempo para criar 100.000 conexões:

  • Antes : 5.916 segundos
  • Após : 2.374 segundos

Suporte para HTTP/2 sobre TLS (HTTPS) no macOS em Kestrel

O .NET 8 adiciona suporte para Application-Layer Protocol Negotiation (ALPN) ao macOS. ALPN é um recurso TLS usado para negociar qual protocolo HTTP uma conexão usará. Por exemplo, o 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 ASP.NET Core Kestrel.

Monitorização de ficheiros de certificados 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 ficheiro de certificado é tratada da mesma forma que uma alteração no caminho configurado (ou seja, as endpoints são recarregadas).

Observe que as exclusões de arquivos não são rastreadas, pois surgem de forma transitória e travariam o servidor se não fossem transitórias.

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

Se o TLS estiver desativado e o HTTP/1.x estiver disponível, HTTP/2 e HTTP/3 serão desativados, mesmo que tenham sido especificados. Isso pode causar algumas surpresas desagradáveis, por isso adicionamos saída de aviso para que você saiba quando isso acontecer.

HTTP_PORTS e HTTPS_PORTS teclas de configuração

Aplicações e contentores geralmente recebem apenas uma porta para escutar, como 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 os servidores Kestrel e HTTP.sys. Estes podem ser definidos com os prefixos de variáveis de ambiente DOTNET_ ou ASPNETCORE_, ou especificados diretamente através de qualquer outra entrada de configuração, como appsettings.json. Cada um é uma lista delimitada por ponto-e-vírgula de valores de portas. Por exemplo:

ASPNETCORE_HTTP_PORTS=80;8080
ASPNETCORE_HTTPS_PORTS=443;8081

Esta é a abreviação do 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 Kestrel e a implementação do servidor Web no ASP.NET CoreHTTP.sys.

Nome SNI do host em ITlsHandshakeFeature

O nome de host SNI (Server Name Indication) agora está exposto na propriedade HostName da interface ITlsHandshakeFeature.

O SNI faz parte do processo de handshake 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 virtuais ou domínios. 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. Mas, 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 de grande escala gerenciando milhares de associações SNI. Esta funcionalidade pode melhorar significativamente a eficiência de depuração durante os escalonamentos por parte dos clientes. A maior 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](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/IHttpSysRequestTimingFeature.cs,3c5dc86dc837b1f4) fornece informações detalhadas de tempo para solicitações ao usar o [HTTP.sys server](xref:fundamentals/servers/httpsys) e [In-process hosting with IIS](xref:host-and-deploy/iis/in-process-hosting?view=aspnetcore-8.0&preserve-view=true#ihsrtf8): [IHttpSysRequestTimingFeature.TryGetTimestamp](https://source.dot.net/#Microsoft.AspNetCore.Server.HttpSys/IHttpSysRequestTimingFeature.cs,3c5dc86dc837b1f4) recupera o carimbo de data/hora para o tipo de temporização 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 detalhadas de temporização com IHttpSysRequestTimingFeature e Informações de temporização e Hospedagem em processo com o IIS.

HTTP.sys: Suporte opt-in para bufferização de resposta em modo núcleo

Em alguns cenários, altos volumes de pequenas gravações com alta latência podem causar um impacto significativo no desempenho de HTTP.sys. Este impacto deve-se à falta de um buffer de Pipe na implementação HTTP.sys. Para melhorar o desempenho nesses cenários, o suporte para buffer de resposta foi adicionado ao HTTP.sys. Habilite o buffer definindo HttpSysOptions.EnableKernelResponseBuffering como true.

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

Os 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. Ativar esse sinalizador pode resultar em maior uso de CPU e memória por HTTP.Sys.

Autenticação e autorização

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

Identity pontos de extremidade da API

MapIdentityApi<TUser> é um novo método de extensão que adiciona dois pontos de extremidade de API (/register e /login). O principal objetivo do MapIdentityApi é tornar mais fácil para os desenvolvedores usarem ASP.NET Core Identity para autenticação em aplicativos de página única (SPA) baseados em JavaScript ou aplicativos Blazor. Em vez de usar a UI padrão fornecida pelo ASP.NET Core Identity, que se baseia em Páginas Razor, o MapIdentityApi adiciona endpoints de API JSON que são mais adequados para aplicações SPA e aplicações não baseadas em navegador. Para obter mais informações, consulte Identity endpoints da API.

IAuthorizationRequirementData

Antes do lançamento do .NET 8, a adição de uma política de autorização parametrizada a um endpoint exigia a implementação:

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

Por exemplo, considere o seguinte código escrito para .NET 7:

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 exemplo completo para .NET 7 ou anterior é o aplicativo de exemplo OldStyleAuthRequirements (dotnet/AspNetCore.Docs.Samples repositório GitHub) (como baixar).

O .NET 8 apresenta a IAuthorizationRequirementData interface. A interface IAuthorizationRequirementData 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 Program.cs atualizado:

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();

A MinimumAgeAuthorizationHandleratualizada :

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

namespace AuthRequirementsData.Authorization;

class MinimumAgeAuthorizationHandler(ILogger<MinimumAgeAuthorizationHandler> logger) 
-    : AuthorizationHandler<MinimumAgeRequirement>
+    : AuthorizationHandler<MinimumAgeAuthorizeAttribute>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
-       MinimumAgeRequirement requirement)
+       MinimumAgeAuthorizeAttribute requirement)
    {
        ...
    }
}

O exemplo atualizado é o aplicativo de exemplo AuthRequirementsData (dotnet/AspNetCore.Docs.Samples repositório GitHub) (como fazer download).

Para obter mais informações, consulte Políticas de autorização personalizadas com 'IAuthorizationRequirementData'.

Protegendo endpoints do Swagger UI

Os endpoints do Swagger UI agora podem ser protegidos em ambientes de produção chamando MapSwagger().RequireAuthorization. Para obter mais informações, consulte Protegendo endpoints do Swagger UI

Miscellaneous

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

Suporte para serviços chaveados na injeção de dependências

Serviços chaveados refere-se a um mecanismo para o registo e recuperação de serviços de injeção de dependências (DI) usando chaves. Um serviço é associado a uma chave chamando AddKeyedSingleton (ou AddKeyedScoped ou AddKeyedTransient) para registrá-lo. 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 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 ASP.NET Core. São fornecidos modelos que criam aplicativos baseados nas tecnologias JavaScript, como Angular, React e Vue. Estes modelos:

  • Crie uma solução do Visual Studio com um projeto de frontend e um projeto de back-end.
  • Use o tipo de projeto Visual Studio para JavaScript e TypeScript (.esproj) para o frontend.
  • Use 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, consulte Visão geral de 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 graças ao suporte para atributos genéricos em 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 são suportadas 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 .NET 8.

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

Ferramentas de rota

ASP.NET Core é construído sobre roteamento. APIs mínimas, APIs da Web, Razor Páginas e Blazor todos 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. Esses novos recursos incluem:

Para obter mais informações, consulte ferramentas de roteamento no .NET 8.

ASP.NET Core métricas

As métricas são medições relatadas ao longo do tempo e são usadas com mais frequência 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 as falhas ultrapassarem um limite.

Esta pré-visualização introduz novas métricas ao longo de 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 medições com contadores, medidores e histogramas.
  • Relatórios robustos com valores multidimensionais.
  • Integração no ecossistema nativo da nuvem mais amplo, alinhando-se com os padrões OpenTelemetry .

Foram adicionadas métricas para hospedagem ASP.NET Core, Kestrele SignalR. Para obter mais informações, consulte System.Diagnostics.Metrics.

IExceptionHandler

IExceptionHandler é uma nova interface que dá ao desenvolvedor uma função de retorno para lidar com exceções conhecidas num local centralizado.

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

Para obter mais informações, consulte IExceptionHandler.

Experiência de depuração melhorada

Os atributos de personalização de depuração foram adicionados a tipos como HttpContext, HttpRequest, HttpResponse, ClaimsPrincipale WebApplication. As exibições aprimoradas do depurador para esses tipos facilitam a localização de informações importantes no depurador de um IDE. As capturas de ecrã a seguir mostram a diferença que os atributos fazem na exibição no depurador de HttpContext.

.NET 7:

Exibição de depurador inútil 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 destaca informações importantes, como pontos de extremidade configurados, camadas de intermediação, e valores IConfiguration.

.NET 7:

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

.NET 8:

Visualização útil para depuração do tipo WebApplication no .NET 8.

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

IPNetwork.Parse e TryParse

Os novos métodos Parse e TryParse no IPNetwork adicionam suporte para a criação de um IPNetwork usando uma cadeia de caracteres de entrada na de notação CIDR ou "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 de 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

ASP.NET Core no .NET 8 adiciona suporte para o uso do Redis como um cache distribuído para cache de saída. A cache de saída é uma funcionalidade que permite a uma aplicação armazenar em cache a saída de um endpoint de API Mínima, ação de controlador ou Razor Página. Para obter mais informações, consulte Cache de saída.

Middleware de curto-circuito após o encaminhamento

Quando o encaminhamento corresponde a um ponto final, geralmente permite que o restante do pipeline de middleware seja executado antes de invocar a lógica do ponto final. Os serviços podem reduzir o uso de recursos filtrando solicitações conhecidas logo 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 por autenticação ou middleware CORS. O exemplo seguinte interrompe solicitações que correspondem à rota /short-circuit:

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

Use o método MapShortCircuit para configurar 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 sondam servidores em busca de caminhos bem conhecidos, como robots.txt e favicon.ico. Se o aplicativo não tiver esses arquivos, uma linha de código poderá configurar ambas as rotas:

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

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

Extensibilidade do middleware de log HTTP

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

  • HttpLoggingFields.Duration: Quando ativado, o middleware emite um novo log no final da solicitação e da resposta que mede o tempo total necessário para o processamento. Este novo campo foi adicionado ao conjunto de HttpLoggingFields.All.
  • HttpLoggingOptions.CombineLogs: Quando ativado, o middleware consolida todos os logs que estão ativados para uma solicitação e resposta num único 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 registado (usando AddHttpLoggingInterceptor) para receber retornos de chamada por requisição e por resposta para personalizar quais detalhes são registados. Todas as configurações de log específicas do ponto de extremidade são aplicadas primeiro e, em seguida, podem ser alteradas nestes callbacks. Uma implementação pode:
    • Inspecione a solicitação e a resposta.
    • É possível ativar ou desativar qualquer HttpLoggingFields.
    • Ajuste a quantidade do corpo da solicitação ou resposta que é registrada.
    • Adicione campos personalizados aos logs.

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

Novas APIs no ProblemDetails para suportar 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 estejam 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 capaz de gerar ProblemDetails. O exemplo a seguir 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 fallback de IProblemDetailsService

Alterações de grande impacto

Use os artigos em Alterações significativas no .NET para encontrar alterações significativas que podem ser aplicadas ao atualizar um aplicativo para uma versão mais recente do .NET.

Recursos adicionais