O que há de novo no ASP.NET Core 6.0
Este artigo destaca as alterações mais significativas no ASP.NET Core 6.0 com links para documentação relevante.
ASP.NET Core MVC e melhorias Razor
APIs mínimas
APIs mínimas são arquitetadas para criar APIs HTTP com dependências mínimas. Eles são ideais para microsserviços e aplicativos que desejam incluir apenas os arquivos, recursos e dependências mínimos no ASP.NET Core. Para mais informações, consulte:
- Tutorial: Criar uma API mínima com ASP.NET Core
- Diferenças entre APIs mínimas e APIs com controladores
- Referência Rápida de APIs Mínimas
- Exemplos de código migrados para o novo modelo de hospedagem mínima em 6.0
SignalR
Tag de atividade de longa duração para conexões SignalR
SignalR usa o novo Microsoft.AspNetCore.Http.Features.IHttpActivityFeature.Activity para adicionar uma tag http.long_running
à atividade de solicitação.
IHttpActivityFeature.Activity
é usado por serviços APM como Azure Monitor Application Insights filtrar solicitações de SignalR da criação de alertas de solicitação de longa execução.
SignalR melhorias de desempenho
- Aloque HubCallerClients uma vez por conexão, em vez de cada chamada de método de hub.
- Evite a alocação de encerramento em SignalR
DefaultHubDispatcher.Invoke
. O estado é passado para uma função estática local através de parâmetros para evitar uma alocação de fechamento. Para obter mais informações, consulte este pull request do GitHub. - Aloque um único StreamItemMessage por fluxo em vez de por item de fluxo no streaming de servidor para cliente. Para mais informações, consulte este pull request do GitHub .
Razor compilador
Razor compilador atualizado para usar geradores de código-fonte
O compilador Razor agora é baseado em geradores de código C# . Os geradores de código-fonte são executados durante a compilação e inspecionam o que está sendo compilado para produzir arquivos adicionais que são compilados junto com o resto do projeto. O uso de geradores de código-fonte simplifica o compilador Razor e acelera significativamente os tempos de compilação.
O compilador Razor já não produz um assembly de Views separado.
O compilador Razor utilizou anteriormente um processo de compilação de duas etapas que produzia um assembly Views separado que continha as visualizações geradas e páginas (arquivos.cshtml
) definidos na aplicação. Os tipos gerados eram públicos e sob o namespace AspNetCore
.
O compilador Razor atualizado cria as visões e os tipos de páginas no assembly do projeto principal. Esses tipos são agora gerados por padrão como selados internos no namespace AspNetCoreGeneratedDocument
. Essa alteração melhora o desempenho da compilação, permite a implantação de um único arquivo e permite que esses tipos participem do Hot Reload.
Para obter mais informações sobre essa alteração, consulte o problema de anúncio relacionado no GitHub.
ASP.NET Melhorias no desempenho principal e na API
Muitas alterações foram feitas para reduzir alocações e melhorar o desempenho em toda a pilha:
- Não alocação aplicativo. Use método de extensão. A nova sobrecarga de
app.Use
requer passar o contexto paranext
, o que elimina duas alocações internas por pedido que são necessárias ao usar a outra sobrecarga. - Alocações de memória reduzidas ao acessar HttpRequest.Cookies. Para obter mais informações, consulte o problema do GitHub .
- Use LoggerMessage.Define somente para Windows HTTP.sys servidor web. As chamadas de métodos de extensão ILogger foram substituídas por chamadas para
LoggerMessage.Define
. - Reduza a sobrecarga em SocketConnection por conexão em ~30%. Para obter mais informações, consulte esta solicitação pull do GitHub.
- Reduza as alocações removendo delegados de log em tipos genéricos. Para obter mais informações, consulte esta solicitação pull do GitHub.
- Acesso GET mais rápido (cerca de 50%) a recursos comumente usados, como IHttpRequestFeature, IHttpResponseFeature, IHttpResponseBodyFeature, IRouteValuesFeaturee IEndpointFeature. Para obter mais informações, consulte esta solicitação pull do GitHub.
- Use cadeias de caracteres de instância única para nomes de cabeçalho conhecidos, mesmo que eles não estejam no bloco de cabeçalho preservado. O uso da cadeia de caracteres de instância única ajuda a evitar várias duplicações da mesma cadeia de caracteres em conexões de longa duração, por exemplo, em Microsoft.AspNetCore.WebSockets. Para obter mais informações, consulte o problema do GitHub
. - Reutilize HttpProtocol CancellationTokenSource em Kestrel. Use o novo método
CancellationTokenSource.TryReset no para reutilizar tokens se eles não tiverem sido cancelados. Para mais informações, consulte este problema do GitHub e este vídeo . - Implemente e utilize um AdaptiveCapacityDictionary naMicrosoft.AspNetCore.HttpRequestCookieCollection para aceder mais eficientemente aos dicionários. Para obter mais informações, consulte este pedido de pull do GitHub.
Pegada de memória reduzida para conexões TLS ociosas
Para conexões TLS de longa execução em que os dados são enviados apenas ocasionalmente, reduzimos significativamente o espaço ocupado pela memória dos aplicativos ASP.NET Core no .NET 6. Isso deve ajudar a melhorar a escalabilidade de cenários como servidores WebSocket. Isso foi possível devido a inúmeras melhorias em System.IO.Pipelines, SslStreame Kestrel. As seções a seguir detalham algumas das melhorias que contribuíram para a redução do espaço ocupado pela memória:
Reduza o tamanho do System.IO.Pipelines.Pipe
Para cada conexão estabelecida, dois tubos são alocados em Kestrel:
- A camada de transporte para a aplicação da solicitação.
- A camada de aplicação para o transporte da resposta.
Ao reduzir o tamanho do System.IO.Pipelines.Pipe de 368 bytes para 264 bytes (uma redução de cerca de 28,2%), são salvos 208 bytes por conexão (104 bytes por tubo).
Pool SocketSender
Objetos SocketSender
que são subclasses de SocketAsyncEventArgsocupam cerca de 350 bytes em tempo de execução. Em vez de alocar um novo objeto SocketSender
por conexão, eles podem ser agrupados.
SocketSender
objetos podem ser agrupados porque os envios geralmente são muito rápidos. O pool reduz a sobrecarga por conexão. Em vez de alocar 350 bytes por conexão, apenas 350 bytes por IOQueue
são alocados. A alocação é feita por fila para evitar contenção. Nosso servidor WebSocket com 5000 conexões ociosas passou de alocar ~1,75 MB (350 bytes * 5000) para alocar ~2,8 kb (350 bytes * 8) para objetos SocketSender
.
Zero bytes lidos com SslStream
As leituras sem buffer são uma técnica empregada no ASP.NET Core para evitar o aluguel de memória do pool de memória se não houver dados disponíveis no soquete. Antes dessa alteração, nosso servidor WebSocket com 5000 conexões ociosas exigia ~200 MB sem TLS em comparação com ~800 MB com TLS. Algumas dessas alocações (4k por conexão) eram de Kestrel ter de manter temporariamente um buffer de ArrayPool<T> enquanto espera pela conclusão das leituras em SslStream. Dado que essas conexões estavam ociosas, nenhuma leitura foi concluída e não devolveram seus buffers para o ArrayPool
, forçando o ArrayPool
a alocar mais memória. As alocações restantes estavam em SslStream
em si: buffer de 4k para handshakes TLS e buffer de 32k para leituras normais. No .NET 6, quando o usuário executa uma leitura de zero byte no SslStream
e não tem dados disponíveis, SslStream
executa internamente uma leitura de zero byte no fluxo encapsulado subjacente. Na melhor das hipóteses (ligação inativa), estas alterações resultam numa poupança de 40 Kb por ligação, permitindo ao mesmo tempo que o consumidor (Kestrel) seja notificado quando os dados estiverem disponíveis sem reter quaisquer buffers não utilizados.
Leituras de zero bytes com o PipeReader
Com leituras sem buffer suportadas no SslStream
, foi adicionada uma opção para executar leituras de zero byte em StreamPipeReader
, o tipo interno que adapta um Stream
num PipeReader
. Em Kestrel, umStreamPipeReader
é usado para adaptar o SslStream
subjacente em um PipeReader
. Portanto, foi necessário expor essas semânticas de leitura de bytes zero no PipeReader
.
Agora pode ser criado um PipeReader
que suporte leituras de zero bytes em qualquer Stream
subjacente que suporte semântica de leitura de zero bytes (por exemplo, SslStream
, NetworkStream, etc) usando a seguinte API:
var reader = PipeReader.Create(stream, new StreamPipeReaderOptions(useZeroByteReads: true));
Remover lajes do SlabMemoryPool
Para reduzir a fragmentação da pilha, o Kestrel utilizou uma técnica em que alocou blocos de memória de 128 KB como parte do seu pool de memória. As lajes foram então divididas em blocos de 4 KB que foram usados por Kestrel internamente. Os blocos tinham que ser maiores que 85 KB para forçar a alocação no amontoado de objetos grandes para evitar que o GC realocasse esta matriz. No entanto, com a introdução da nova geração GC, Pinned Object Heap (POH), não faz mais sentido alocar blocos na laje. Kestrel agora aloca blocos diretamente no POH, reduzindo a complexidade envolvida no gerenciamento do pool de memória. Essa alteração deve facilitar a execução de melhorias futuras, como facilitar a redução do pool de memória usado por Kestrel.
IAsyncDisposable suportado
IAsyncDisposable agora está disponível para controladores, páginas Razor e componentes de exibição. Versões assíncronas foram adicionadas às interfaces relevantes em fábricas e ativadores:
- Os novos métodos oferecem uma implementação padrão de interface que delega para a versão síncrona e invoca Dispose.
- As implementações substituem a implementação padrão e lidam com a eliminação das implementações
IAsyncDisposable
. - As implementações favorecem
IAsyncDisposable
em detrimento deIDisposable
quando ambas as interfaces são implementadas. - Os extensores devem substituir os novos métodos incluídos para dar suporte a instâncias
IAsyncDisposable
.
IAsyncDisposable
é útil ao trabalhar com:
- Enumeradores assíncronos, por exemplo, em fluxos assíncronos.
- Recursos não gerenciados que têm operações de E/S com uso intensivo de recursos para liberar.
Ao implementar essa interface, use o método DisposeAsync
para liberar recursos.
Considere um controlador que cria e usa um Utf8JsonWriter.
Utf8JsonWriter
é um recurso IAsyncDisposable
:
public class HomeController : Controller, IAsyncDisposable
{
private Utf8JsonWriter? _jsonWriter;
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
_jsonWriter = new Utf8JsonWriter(new MemoryStream());
}
IAsyncDisposable
deve implementar DisposeAsync
:
public async ValueTask DisposeAsync()
{
if (_jsonWriter is not null)
{
await _jsonWriter.DisposeAsync();
}
_jsonWriter = null;
}
Porta Vcpkg para SignalR cliente C++
Vcpkg é um gerenciador de pacotes de linha de comando multiplataforma para bibliotecas C e C++. Recentemente, adicionamos uma porta ao vcpkg
para adicionar CMake
suporte nativo para o cliente C++ SignalR.
vcpkg
também funciona com MSBuild.
O cliente SignalR pode ser adicionado a um projeto CMake com o seguinte trecho quando o vcpkg é incluído no arquivo toolchain:
find_package(microsoft-signalr CONFIG REQUIRED)
link_libraries(microsoft-signalr::microsoft-signalr)
Com o trecho anterior, o cliente SignalR C++ está pronto para usar #include
e usado em um projeto sem qualquer configuração adicional. Para obter um exemplo completo de uma aplicação que utiliza o cliente C++
Blazor
Alterações no modelo de projeto
Várias alterações de modelo de projeto foram feitas para aplicativos Blazor, incluindo o uso do arquivo Pages/_Layout.cshtml
para conteúdo de layout que aparecia no arquivo _Host.cshtml
para aplicativos Blazor Server anteriores. Estude as alterações criando um aplicativo a partir de um modelo de projeto 6.0 ou acessando a fonte de referência ASP.NET Core para os modelos de projeto:
Blazor WebAssembly suporte a dependências nativas
Blazor WebAssembly aplicativos podem usar dependências nativas criadas para serem executadas no WebAssembly. Para obter mais informações, consulte ASP.NET Core Blazor WebAssembly dependências nativas.
Compilação do WebAssembly Ahead-of-time (AOT) e revinculação de tempo de execução
Blazor WebAssembly suporta compilação ahead-of-time (AOT), onde você pode compilar seu código .NET diretamente no WebAssembly. A compilação AOT resulta em melhorias de desempenho em tempo de execução às custas de um tamanho de aplicativo maior. Revincular o tempo de execução do .NET WebAssembly corta o código de tempo de execução não utilizado e, portanto, melhora a velocidade de download. Para obter mais informações, consulte compilação Ahead-of-time (AOT), e relinking em tempo de execução.
Persistir o estado pré-renderizado
Blazor suporta o estado persistente em uma página pré-renderizada para que o estado não precise ser recriado quando o aplicativo estiver totalmente carregado. Para obter mais informações, consulte integrar ASP.NET componentes principais do Razor com o MVC ou Razor Pages.
Limites de erro
Os limites de erro fornecem uma abordagem conveniente para lidar com exceções no nível da interface do usuário. Para obter mais informações, consulte Manipular erros em aplicativos ASP.NET Core Blazor.
Suporte SVG
O elemento <foreignObject>
é suportado para exibir HTML arbitrário dentro de um SVG. Para obter mais informações, consulte componentes do ASP.NET Core Razor.
Blazor Server suporte para transferência de matriz de bytes no JS Interop
Blazor suporta uma interoperabilidade otimizada de matriz de bytes JS que evita a codificação e descodificação de matrizes de bytes em Base64. Para obter mais informações, consulte os seguintes recursos:
- Chamar funções JavaScript a partir de métodos .NET no ASP.NET Core Blazor
- Chamar métodos .NET a partir de funções JavaScript no ASP.NET Core Blazor
Melhorias na string de consulta
O suporte para trabalhar com cadeias de caracteres de consulta foi melhorado. Para obter mais informações, consulte ASP.NET Core Blazor roteamento e navegação.
Atribuição para selecionar múltiplos
A vinculação suporta a seleção de várias opções com <input>
elementos. Para obter mais informações, consulte os seguintes recursos:
Controle de conteúdo do cabeçalho (<head>
)
Razor componentes podem modificar o conteúdo do elemento HTML <head>
de uma página, incluindo definir o título da página (elemento<title>
) e modificar os metadados (elementos<meta>
). Para obter mais informações, consulte o conteúdo do Control <head>
em aplicações ASP.NET Core Blazor.
Gerar componentes Angular e React
Gere componentes JavaScript específicos da estrutura a partir de componentes Razor para estruturas da Web, como Angular ou React. Para obter mais informações, consulte componentes do ASP.NET Core Razor.
Renderizar componentes a partir de JavaScript
Renderize componentes Razor dinamicamente a partir do JavaScript para aplicativos JavaScript existentes. Para obter mais informações, consulte componentes ASP.NET Core Razor.
Elementos personalizados
O suporte experimental está disponível para a criação de elementos personalizados, que usam interfaces HTML padrão. Para obter mais informações, consulte componentes do ASP.NET Core Razor.
Inferir tipos genéricos de componentes a partir de componentes ancestrais
Um componente ancestral pode cascatar um parâmetro de tipo por nome para descendentes usando o novo atributo [CascadingTypeParameter]
. Para obter mais informações, consulte componentes do ASP.NET Core Razor.
Componentes renderizados dinamicamente
Use o novo componente DynamicComponent
interno para renderizar componentes por tipo. Para mais informações, veja componentes do ASP.NET Core renderizados dinamicamente Razor.
Acessibilidade Blazor melhorada
Use o novo componente FocusOnNavigate
para definir o foco da interface do usuário para um elemento baseado em um seletor CSS depois de navegar de uma página para outra. Para obter mais informações, consulte ASP.NET Core Blazor roteamento e navegação.
Suporte a argumentos de eventos personalizados
Blazor oferece suporte a argumentos de evento personalizados, que permitem que você passe dados arbitrários para manipuladores de eventos .NET com eventos personalizados. Para obter mais informações, consulte ASP.NET Core Blazor de manipulação de eventos.
Parâmetros necessários
Aplique o novo atributo [EditorRequired]
para especificar um parâmetro de componente necessário. Para obter mais informações, consulte componentes do ASP.NET Core Razor.
Posicionamento de ficheiros JavaScript com páginas, visualizações e componentes
Coloque arquivos JavaScript para páginas, exibições e componentes Razor como uma maneira conveniente de organizar scripts em um aplicativo. Para obter mais informações, consulte ASP.NET Core Blazor interoperabilidade JavaScript (JS interop).
Inicializadores JavaScript
Os inicializadores JavaScript executam a lógica antes e depois de Blazor um aplicativo ser carregado. Para obter mais informações, consulte ASP.NET Interoperabilidade do Core Blazor JavaScript (JS interoperabilidade).
Interoperabilidade de streaming JavaScript
Blazor agora suporta streaming de dados diretamente entre .NET e JavaScript. Para obter mais informações, consulte os seguintes recursos:
Restrições de tipo genéricas
Parâmetros de tipo genéricos agora são suportados. Para obter mais informações, consulte os componentes do ASP.NET Core Razor.
Layout de implantação do WebAssembly
Use um layout de implantação para habilitar downloads de aplicativos Blazor WebAssembly em ambientes de segurança restritos. Para obter mais informações, consulte layout de implantação para aplicativos Blazor WebAssembly hospedados ASP.NET Core.
Novos artigos Blazor
Para além das características Blazor descritas nas secções anteriores, estão disponíveis novos artigos Blazor sobre os seguintes temas:
-
ASP.NET Core Blazor transferências de ficheiros: Saiba como baixar um ficheiro usando interoperabilidade de streaming
byte[]
nativo para garantir uma transferência eficiente para o cliente. - Exibir imagens e documentos no ASP.NET Core Blazor: Descubra como trabalhar com imagens e documentos em aplicativos Blazor, incluindo como transmitir dados de imagens e documentos.
Crie aplicativos Blazor Hybrid com .NET MAUI, WPF e Windows Forms
Use Blazor Hybrid para misturar estruturas de cliente nativo para desktop e dispositivos móveis com .NET e Blazor:
- .NET Multi-platform App UI (.NET MAUI) é uma estrutura multiplataforma para criar aplicativos móveis e de desktop nativos com C# e XAML.
- Blazor Hybrid aplicações podem ser criadas com os frameworks Windows Presentation Foundation (WPF) e Windows Forms.
Importante
Blazor Hybrid está em pré-visualização e não deve ser usado em aplicativos de produção até o lançamento final.
Para obter mais informações, consulte os seguintes recursos:
- Pré-visualização da documentação do ASP.NET Core Blazor Hybrid
- O que é .NET MAUI?
- Microsoft .NET Blog (categoria: ".NET MAUI")
Kestrel
HTTP/3 está atualmente em rascunho e, portanto, sujeito a alterações. O suporte a HTTP/3 no ASP.NET Core não foi lançado, é um recurso de visualização incluído no .NET 6.
Kestrel agora suporta HTTP/3. Para obter mais informações, consulte Usar HTTP/3 com o servidor Web do ASP.NET Core Kestrel e a entrada de blog suporte para HTTP/3 no .NET 6.
Novas categorias de registo de Kestrel para registo selecionado
Antes dessa alteração, habilitar o registro detalhado para Kestrel era proibitivamente caro, pois todos Kestrel compartilhavam o nome da categoria de registro Microsoft.AspNetCore.Server.Kestrel
.
Microsoft.AspNetCore.Server.Kestrel
ainda está disponível, mas as seguintes novas subcategorias permitem um maior controle do registo:
-
Microsoft.AspNetCore.Server.Kestrel
(categoria atual):ApplicationError
,ConnectionHeadResponseBodyWrite
,ApplicationNeverCompleted
,RequestBodyStart
,RequestBodyDone
,RequestBodyNotEntirelyRead
,RequestBodyDrainTimedOut
,ResponseMinimumDataRateNotSatisfied
,InvalidResponseHeaderRemoved
,HeartbeatSlow
. -
Microsoft.AspNetCore.Server.Kestrel.BadRequests
:ConnectionBadRequest
,RequestProcessingError
,RequestBodyMinimumDataRateNotSatisfied
. -
Microsoft.AspNetCore.Server.Kestrel.Connections
:ConnectionAccepted
,ConnectionStart
,ConnectionStop
,ConnectionPause
,ConnectionResume
,ConnectionKeepAlive
,ConnectionRejected
,ConnectionDisconnect
,NotAllConnectionsClosedGracefully
,NotAllConnectionsAborted
,ApplicationAbortedConnection
. -
Microsoft.AspNetCore.Server.Kestrel.Http2
:Http2ConnectionError
,Http2ConnectionClosing
,Http2ConnectionClosed
,Http2StreamError
,Http2StreamResetAbort
,HPackDecodingError
,HPackEncodingError
,Http2FrameReceived
,Http2FrameSending
,Http2MaxConcurrentStreamsReached
. -
Microsoft.AspNetCore.Server.Kestrel.Http3
:Http3ConnectionError
,Http3ConnectionClosing
,Http3ConnectionClosed
,Http3StreamAbort
,Http3FrameReceived
,Http3FrameSending
.
As regras existentes continuam a funcionar, mas agora pode ser mais seletivo quanto às regras que permite. Por exemplo, a sobrecarga de observabilidade de ativar os registos Debug
apenas para pedidos incorretos é significativamente reduzida e pode ser realizada com a seguinte configuração:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.Kestrel.BadRequests": "Debug"
}
}
A filtragem de registos aplica regras com o prefixo mais longo correspondente à categoria. Para obter mais informações, consulte Como as regras de filtragem são aplicadas
Emit KestrelServerOptions via evento EventSource
O KestrelEventSource emite um novo evento contendo o KestrelServerOptions serializado por JSON quando ativado com verbosidade EventLevel.LogAlways
. Esse evento torna mais fácil raciocinar sobre o comportamento do servidor ao analisar os rastreamentos coletados. O JSON a seguir é um exemplo da carga útil do evento:
{
"AllowSynchronousIO": false,
"AddServerHeader": true,
"AllowAlternateSchemes": false,
"AllowResponseHeaderCompression": true,
"EnableAltSvc": false,
"IsDevCertLoaded": true,
"RequestHeaderEncodingSelector": "default",
"ResponseHeaderEncodingSelector": "default",
"Limits": {
"KeepAliveTimeout": "00:02:10",
"MaxConcurrentConnections": null,
"MaxConcurrentUpgradedConnections": null,
"MaxRequestBodySize": 30000000,
"MaxRequestBufferSize": 1048576,
"MaxRequestHeaderCount": 100,
"MaxRequestHeadersTotalSize": 32768,
"MaxRequestLineSize": 8192,
"MaxResponseBufferSize": 65536,
"MinRequestBodyDataRate": "Bytes per second: 240, Grace Period: 00:00:05",
"MinResponseDataRate": "Bytes per second: 240, Grace Period: 00:00:05",
"RequestHeadersTimeout": "00:00:30",
"Http2": {
"MaxStreamsPerConnection": 100,
"HeaderTableSize": 4096,
"MaxFrameSize": 16384,
"MaxRequestHeaderFieldSize": 16384,
"InitialConnectionWindowSize": 131072,
"InitialStreamWindowSize": 98304,
"KeepAlivePingDelay": "10675199.02:48:05.4775807",
"KeepAlivePingTimeout": "00:00:20"
},
"Http3": {
"HeaderTableSize": 0,
"MaxRequestHeaderFieldSize": 16384
}
},
"ListenOptions": [
{
"Address": "https://127.0.0.1:7030",
"IsTls": true,
"Protocols": "Http1AndHttp2"
},
{
"Address": "https://[::1]:7030",
"IsTls": true,
"Protocols": "Http1AndHttp2"
},
{
"Address": "http://127.0.0.1:5030",
"IsTls": false,
"Protocols": "Http1AndHttp2"
},
{
"Address": "http://[::1]:5030",
"IsTls": false,
"Protocols": "Http1AndHttp2"
}
]
}
Novo evento DiagnosticSource para solicitações HTTP rejeitadas
Kestrel agora emite um novo evento DiagnosticSource
para solicitações HTTP rejeitadas na camada do servidor. Antes dessa alteração, não havia como observar esses pedidos rejeitados. O novo evento DiagnosticSource
Microsoft.AspNetCore.Server.Kestrel.BadRequest
contém um IBadRequestExceptionFeature que pode ser usado para introspeccionar o motivo da rejeição da solicitação.
using Microsoft.AspNetCore.Http.Features;
using System.Diagnostics;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var diagnosticSource = app.Services.GetRequiredService<DiagnosticListener>();
using var badRequestListener = new BadRequestEventListener(diagnosticSource,
(badRequestExceptionFeature) =>
{
app.Logger.LogError(badRequestExceptionFeature.Error, "Bad request received");
});
app.MapGet("/", () => "Hello world");
app.Run();
class BadRequestEventListener : IObserver<KeyValuePair<string, object>>, IDisposable
{
private readonly IDisposable _subscription;
private readonly Action<IBadRequestExceptionFeature> _callback;
public BadRequestEventListener(DiagnosticListener diagnosticListener,
Action<IBadRequestExceptionFeature> callback)
{
_subscription = diagnosticListener.Subscribe(this!, IsEnabled);
_callback = callback;
}
private static readonly Predicate<string> IsEnabled = (provider) => provider switch
{
"Microsoft.AspNetCore.Server.Kestrel.BadRequest" => true,
_ => false
};
public void OnNext(KeyValuePair<string, object> pair)
{
if (pair.Value is IFeatureCollection featureCollection)
{
var badRequestFeature = featureCollection.Get<IBadRequestExceptionFeature>();
if (badRequestFeature is not null)
{
_callback(badRequestFeature);
}
}
}
public void OnError(Exception error) { }
public void OnCompleted() { }
public virtual void Dispose() => _subscription.Dispose();
}
Para obter mais informações, consulte Registo de logs e diagnósticos no Kestrel.
Criar um ConnectionContext a partir de um soquete de aceitação
O novo SocketConnectionContextFactory possibilita a criação de um ConnectionContext a partir de um soquete aceito. Isso torna possível criar um IConnectionListenerFactory personalizado baseado em sockets sem perder todo o trabalho de desempenho e pool realizado em SocketConnection.
Veja este exemplo de um IConnectionListenerFactory personalizado que mostra como utilizar este SocketConnectionContextFactory
.
Kestrel é o perfil de inicialização padrão para o Visual Studio
O perfil de inicialização padrão para todos os novos projetos da Web dotnet é Kestrel. Iniciar Kestrel é significativamente mais rápido e resulta em uma experiência mais responsiva durante o desenvolvimento de aplicativos.
O IIS Express ainda está disponível como um perfil de inicialização para cenários como a Autenticação do Windows ou o compartilhamento de portas.
As portas Localhost para Kestrel são aleatórias
Consulte Portas geradas por modelo para Kestrel neste documento para obter mais informações.
Autenticação e autorização
Servidores de autenticação
O .NET 3 até ao .NET 5 utilizou IdentityServer4 como parte do nosso modelo para dar suporte à emissão de tokens JWT para aplicações SPA e Blazor. Os modelos agora usam o Duende Identity Server.
Se você estiver estendendo os modelos de identidade e estiver atualizando projetos existentes, atualize os namespaces em seu código de IdentityServer4.IdentityServer
para Duende.IdentityServer
e siga as instruções de migração.
O modelo de licença do Duende Identity Server foi alterado para uma licença recíproca, que pode exigir taxas de licença quando é usado comercialmente na produção. Consulte a página de licença Duende para obter mais detalhes.
Negociação de certificado de cliente atrasada
Agora, os desenvolvedores podem optar por usar a negociação de certificado de cliente atrasada especificando ClientCertificateMode.DelayCertificate no HttpsConnectionAdapterOptions. Isso só funciona com conexões HTTP/1.1 porque HTTP/2 proíbe a renegociação atrasada de certificados. O chamador desta API deve armazenar em buffer o corpo da solicitação antes de solicitar o certificado do cliente:
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Microsoft.AspNetCore.WebUtilities;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseKestrel(options =>
{
options.ConfigureHttpsDefaults(adapterOptions =>
{
adapterOptions.ClientCertificateMode = ClientCertificateMode.DelayCertificate;
});
});
var app = builder.Build();
app.Use(async (context, next) =>
{
bool desiredState = GetDesiredState();
// Check if your desired criteria is met
if (desiredState)
{
// Buffer the request body
context.Request.EnableBuffering();
var body = context.Request.Body;
await body.DrainAsync(context.RequestAborted);
body.Position = 0;
// Request client certificate
var cert = await context.Connection.GetClientCertificateAsync();
// Disable buffering on future requests if the client doesn't provide a cert
}
await next(context);
});
app.MapGet("/", () => "Hello World!");
app.Run();
OnCheckSlidingExpiration
evento para controlar a renovação cookie
Cookie expiração deslizante de autenticação agora pode ser personalizada ou suprimida usando o novo OnCheckSlidingExpiration. Por exemplo, esse evento pode ser usado por um aplicativo de página única que precisa executar ping periodicamente no servidor sem afetar a sessão de autenticação.
Diversos
Recarga instantânea
Faça rapidamente atualizações de interface do usuário e código para aplicativos em execução sem perder o estado do aplicativo para uma experiência de desenvolvedor mais rápida e produtiva usando Hot Reload. Para obter mais informações, consulte suporte do .NET Hot Reload para ASP.NET Core e Atualização sobre o progresso do .NET Hot Reload e destaques do Visual Studio 2022.
Modelos melhorados de aplicação de página única (SPA)
Os modelos de projeto ASP.NET Core foram atualizados para Angular e React para usar um padrão aprimorado para aplicativos de página única que é mais flexível e mais alinhado com padrões comuns para o desenvolvimento Web front-end moderno.
Anteriormente, o modelo ASP.NET Core para Angular e React usava middleware especializado durante o desenvolvimento para iniciar o servidor de desenvolvimento para a estrutura front-end e, em seguida, solicitações de proxy do ASP.NET Core para o servidor de desenvolvimento. A lógica para iniciar o servidor de desenvolvimento front-end era específica para a interface de linha de comandos do respetivo framework front-end. Suportar estruturas front-end adicionais usando esse padrão significava adicionar lógica adicional ao ASP.NET Core.
Os modelos ASP.NET Core atualizados para Angular e React no .NET 6 invertem essa disposição e aproveitam o suporte de proxy interno nos servidores de desenvolvimento da maioria das estruturas front-end modernas. Quando a aplicação ASP.NET Core é iniciada, o servidor de desenvolvimento do front-end é iniciado tal como antes, mas o servidor de desenvolvimento é configurado para encaminhar pedidos para o processo ASP.NET Core de back-end. Toda a configuração específica do front-end para configurar o proxy faz parte do aplicativo, não ASP.NET Core. Configurar projetos ASP.NET Core para trabalhar com outras estruturas front-end agora é simples: configure o servidor de desenvolvimento front-end para a estrutura escolhida para proxy para o backend ASP.NET Core usando o padrão estabelecido nos modelos Angular e React.
O código de inicialização do aplicativo ASP.NET Core não precisa mais de nenhuma lógica específica do aplicativo de página única. A lógica para iniciar o servidor de desenvolvimento front-end durante o desenvolvimento é injetada no aplicativo em tempo de execução pelo novo pacote Microsoft.AspNetCore.SpaProxy. O roteamento de fallback é tratado usando o roteamento de ponto final em vez do middleware específico do SPA.
Os modelos que seguem esse padrão ainda podem ser executados como um único projeto no Visual Studio ou usando dotnet run
da linha de comando. Quando o aplicativo é publicado, o código front-end na pasta
Suporte a rascunho HTTP/3 no .NET 6
HTTP/3 está atualmente em rascunho e, portanto, sujeito a alterações. O suporte a HTTP/3 no ASP.NET Core não foi lançado, é um recurso de visualização incluído no .NET 6.
Consulte a entrada de blog suporte a HTTP/3 no .NET 6.
Anotações de tipo de referência anuláveis
Partes do código-fonte do ASP.NET Core 6.0 teve anotações de anulabilidade aplicadas.
Ao utilizar o novo recurso Nullable no C# 8, ASP.NET Core pode fornecer segurança adicional em tempo de compilação no processamento de tipos de referência. Por exemplo, protegendo contra exceções de referência null
. Os projetos que optaram por usar anotações anuláveis podem ver novos avisos durante a compilação de APIs ASP.NET Core.
Para habilitar tipos de referência anuláveis, adicione a seguinte propriedade aos arquivos de projeto:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
Para obter mais informações, consulte Tipos de referência anuláveis.
Análise do código-fonte
Vários analisadores de plataforma de compilador .NET foram adicionados que inspecionam o código do aplicativo em busca de problemas, como configuração ou ordem incorreta de middleware, conflitos de roteamento, etc. Para obter mais informações, consulte Análise de código em ASP.NET aplicativos principais.
Melhorias no modelo de aplicativo Web
Os modelos de aplicativo Web:
- Use o novo modelo de alojamento minimalista.
- Reduz significativamente o número de arquivos e linhas de código necessários para criar um aplicativo. Por exemplo, o aplicativo Web vazio ASP.NET Core cria um arquivo C# com quatro linhas de código e é um aplicativo completo.
- Unifica
Startup.cs
eProgram.cs
em um único arquivoProgram.cs
. - Usa instruções de nível superior para minimizar o código necessário para uma aplicação.
- Usa diretivas globais
using
para eliminar ou minimizar o número necessário de linhas de instruçãousing
.
Portas geradas por modelo para Kestrel
Portas aleatórias são atribuídas durante a criação do projeto para uso pelo servidor Web Kestrel. Portas aleatórias ajudam a minimizar um conflito de portas quando vários projetos são executados na mesma máquina.
Quando um projeto é criado, uma porta HTTP aleatória entre 5000-5300 e uma porta HTTPS aleatória entre 7000-7300 é especificada no arquivo Properties/launchSettings.json
gerado. As portas podem ser alteradas no arquivo Properties/launchSettings.json
. Se nenhuma porta for especificada, por defeito, Kestrel utiliza as portas HTTP 5000 e HTTPS 5001. Para obter mais informações, consulte Configurar pontos de extremidade para o servidor Web ASP.NET Core Kestrel.
Novos padrões de registro em log
Foram introduzidas as seguintes alterações tanto no appsettings.json
como no appsettings.Development.json
:
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
+ "Microsoft.AspNetCore": "Warning"
A alteração de "Microsoft": "Warning"
para "Microsoft.AspNetCore": "Warning"
resulta no registro em log de todas as mensagens informativas do namespace Microsoft
excetoMicrosoft.AspNetCore
. Por exemplo, Microsoft.EntityFrameworkCore
agora é registrado no nível informativo.
Página de Exceção do Desenvolvedor com Middleware adicionado automaticamente
No ambiente de desenvolvimento , o DeveloperExceptionPageMiddleware é adicionado por padrão. Não é mais necessário adicionar o seguinte código aos aplicativos de interface do usuário da Web:
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
Suporte para cabeçalhos de solicitação codificados Latin1 em HttpSysServer
HttpSysServer
agora oferece suporte à decodificação de cabeçalhos de solicitação que Latin1
são codificados definindo a propriedade UseLatin1RequestHeaders em HttpSysOptions para true
:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys(o => o.UseLatin1RequestHeaders = true);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Os logs do módulo ASP.NET Core incluem carimbos de data/hora e PID
Os logs de diagnóstico aprimorados do ASP.NET Core Module (ANCM) para IIS (ANCM) incluem carimbos de data/hora e PID do processo que emite os logs. O registo de carimbos de data/hora e PID ajuda a diagnosticar problemas nas reinicializações de processos que se sobrepõem no IIS quando vários processos de trabalho do IIS estão em execução.
Os logs resultantes agora se assemelham à saída de exemplo mostrada abaixo:
[2021-07-28T19:23:44.076Z, PID: 11020] [aspnetcorev2.dll] Initializing logs for 'C:\<path>\aspnetcorev2.dll'. Process Id: 11020. File Version: 16.0.21209.0. Description: IIS ASP.NET Core Module V2. Commit: 96475a2acdf50d7599ba8e96583fa73efbe27912.
[2021-07-28T19:23:44.079Z, PID: 11020] [aspnetcorev2.dll] Resolving hostfxr parameters for application: '.\InProcessWebSite.exe' arguments: '' path: 'C:\Temp\e86ac4e9ced24bb6bacf1a9415e70753\'
[2021-07-28T19:23:44.080Z, PID: 11020] [aspnetcorev2.dll] Known dotnet.exe location: ''
Tamanho do buffer de entrada não consumido configurável para o IIS
Anteriormente, o servidor IIS armazenava em buffer apenas 64 KiB de corpos de solicitação não consumidos. O buffer de 64 KiB resultou em leituras restritas a esse tamanho máximo, o que afeta o desempenho com grandes corpos de entrada, como uploads. No .NET 6, o tamanho do buffer padrão muda de 64 KiB para 1 MiB, o que deve melhorar a taxa de transferência para carregamentos grandes. Em nossos testes, um upload de 700 MiB que costumava levar 9 segundos agora leva apenas 2,5 segundos.
A desvantagem de um tamanho de buffer maior é um maior consumo de memória por solicitação quando o aplicativo não está lendo rapidamente do corpo da solicitação. Assim, além de alterar o tamanho do buffer padrão, o tamanho do buffer é configurável, permitindo que os aplicativos configurem o tamanho do buffer com base na carga de trabalho.
Ver Auxiliares de Etiquetas de Componentes
Considere um componente de exibição com um parâmetro opcional, conforme mostrado no código a seguir:
class MyViewComponent
{
IViewComponentResult Invoke(bool showSomething = false) { ... }
}
Com o ASP.NET Core 6, o auxiliar de tag pode ser invocado sem precisar especificar um valor para o parâmetro showSomething
:
<vc:my />
Modelo angular atualizado para Angular 12
O modelo ASP.NET Core 6.0 para Angular agora usa o Angular 12.
O modelo React foi atualizado para React 17.
Limite de buffer configurável antes de gravar em disco em Json.NET formatador de saída
Nota: Recomendamos o uso do formatador de saída System.Text.Json, exceto quando o serializador Newtonsoft.Json
for necessário por motivos de compatibilidade. O System.Text.Json
serializador é totalmente async
e funciona de forma eficiente para grandes volumes de dados.
Por padrão, o formatador de saída Newtonsoft.Json
armazena em memória as respostas até 32 KiB antes de armazená-las no disco. Isso é para evitar a execução de E/S síncronas, o que pode resultar em outros efeitos colaterais, como inanição de thread e bloqueios de aplicativos. No entanto, se a resposta for maior que 32 KiB, ocorre uma entrada/saída (E/S) de disco considerável. O limite de memória agora é configurável por meio da propriedade MvcNewtonsoftJsonOptions.OutputFormatterMemoryBufferThreshold antes do buffer no disco:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages()
.AddNewtonsoftJson(options =>
{
options.OutputFormatterMemoryBufferThreshold = 48 * 1024;
});
var app = builder.Build();
Para obter mais informações, consulte este de solicitação pull do GitHub e o arquivo NewtonsoftJsonOutputFormatterTest.cs.
Obtenção e definição mais rápida de cabeçalhos HTTP
Novas APIs foram adicionadas para expor todos os cabeçalhos comuns disponíveis no Microsoft.Net.Http.Headers.HeaderNames como propriedades no IHeaderDictionary resultando em uma API mais fácil de usar. Por exemplo, o middleware em linha no código a seguir obtém e define cabeçalhos de solicitação e resposta usando as novas APIs:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Use(async (context, next) =>
{
var hostHeader = context.Request.Headers.Host;
app.Logger.LogInformation("Host header: {host}", hostHeader);
context.Response.Headers.XPoweredBy = "ASP.NET Core 6.0";
await next.Invoke(context);
var dateHeader = context.Response.Headers.Date;
app.Logger.LogInformation("Response date: {date}", dateHeader);
});
app.Run();
Para cabeçalhos implementados, os acessores get e set são implementados indo diretamente para o campo e omitindo a pesquisa. Para cabeçalhos não implementados, os acessores podem ignorar a pesquisa inicial nos cabeçalhos implementados e executar diretamente a pesquisa Dictionary<string, StringValues>
. Evitar a pesquisa resulta em acesso mais rápido para ambos os cenários.
Streaming assíncrono
ASP.NET Core agora suporta streaming assíncrono de ações do controlador e respostas do formatador JSON. O retorno de um IAsyncEnumerable
de uma ação não armazena mais em buffer o conteúdo da resposta na memória antes de ser enviado. Não armazenar em buffer ajuda a reduzir o uso de memória ao retornar grandes conjuntos de dados que podem ser enumerados de forma assíncrona.
Observe que o Entity Framework Core fornece implementações de IAsyncEnumerable
para consultar o banco de dados. O suporte aprimorado para IAsyncEnumerable
no ASP.NET Core no .NET 6 pode tornar o uso do EF Core com o ASP.NET Core mais eficiente. Por exemplo, o código a seguir não armazena mais os dados do produto na memória antes de enviar a resposta:
public IActionResult GetMovies()
{
return Ok(_context.Movie);
}
No entanto, ao usar o carregamento lento no EF Core, esse novo comportamento pode resultar em erros devido à execução simultânea de consultas enquanto os dados estão sendo enumerados. Os aplicativos podem reverter para o comportamento anterior armazenando os dados em buffer:
public async Task<IActionResult> GetMovies2()
{
return Ok(await _context.Movie.ToListAsync());
}
Consulte o anúncio relacionado para obter detalhes adicionais sobre esta mudança de comportamento.
Middleware de log HTTP
O log HTTP é um novo middleware interno que registra informações sobre solicitações HTTP e respostas HTTP, incluindo os cabeçalhos e o corpo inteiro:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseHttpLogging();
app.MapGet("/", () => "Hello World!");
app.Run();
Navegando para /
com o código anterior gera informações de log semelhantes à seguinte saída:
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
Request:
Protocol: HTTP/2
Method: GET
Scheme: https
PathBase:
Path: /
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cache-Control: max-age=0
Connection: close
Cookie: [Redacted]
Host: localhost:44372
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.30
sec-ch-ua: [Redacted]
sec-ch-ua-mobile: [Redacted]
sec-ch-ua-platform: [Redacted]
upgrade-insecure-requests: [Redacted]
sec-fetch-site: [Redacted]
sec-fetch-mode: [Redacted]
sec-fetch-user: [Redacted]
sec-fetch-dest: [Redacted]
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2]
Response:
StatusCode: 200
Content-Type: text/plain; charset=utf-8
A saída anterior foi habilitada com o seguinte arquivo appsettings.Development.json
:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
}
}
}
O registo HTTP fornece os registos de:
- Informações de solicitação HTTP
- Propriedades comuns
- Cabeçalhos
- Corpo
- Informações de resposta HTTP
Para configurar o middleware de log HTTP, especifique HttpLoggingOptions:
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
// Customize HTTP logging.
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("My-Request-Header");
logging.ResponseHeaders.Add("My-Response-Header");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
});
var app = builder.Build();
app.UseHttpLogging();
app.MapGet("/", () => "Hello World!");
app.Run();
IConnectionSocketFeature
O recurso de solicitação IConnectionSocketFeature fornece acesso ao soquete de aceitação subjacente associado à solicitação atual. Pode ser acedido através do FeatureCollection em HttpContext
.
Por exemplo, o aplicativo a seguir define a propriedade LingerState no soquete aceito:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureEndpointDefaults(listenOptions => listenOptions.Use((connection, next) =>
{
var socketFeature = connection.Features.Get<IConnectionSocketFeature>();
socketFeature.Socket.LingerState = new LingerOption(true, seconds: 10);
return next();
}));
});
var app = builder.Build();
app.MapGet("/", (Func<string>)(() => "Hello world"));
await app.RunAsync();
Restrições de tipo genéricas no Razor
Ao definir parâmetros de tipo genéricos em Razor usando a diretiva @typeparam
, restrições de tipo genérico agora podem ser especificadas usando a sintaxe C# padrão:
Scripts menores para SignalR, Blazor Servere MessagePack
Os scripts SignalR, MessagePack e Blazor Server agora são significativamente menores, permitindo downloads menores, menos análise e compilação de JavaScript pelo navegador e inicialização mais rápida. As reduções de tamanho:
-
signalr.js
: 70% -
blazor.server.js
: 45%
Os roteiros menores são resultado de uma contribuição da comunidade de Ben Adams. Para obter mais informações sobre os detalhes da redução de tamanho, consulte o pull requestdo GitHub de Ben
Ativar sessões de criação de perfil Redis
Uma contribuição da comunidade de Gabriel Lucaci permite uma sessão de perfilagem do Redis com o Microsoft.Extensions.Caching.StackExchangeRedis:
using StackExchange.Redis.Profiling;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddStackExchangeRedisCache(options =>
{
options.ProfilingSession = () => new ProfilingSession();
});
Para obter mais informações, consulte StackExchange.Redis Profiling.
Cópia de sombra no IIS
Um recurso experimental foi adicionado ao ASP.NET Core Module (ANCM) para IIS para adicionar suporte para assemblies de aplicativos de cópia de sombra. Atualmente, o .NET bloqueia binários de aplicativos quando executado no Windows, tornando impossível substituir binários quando o aplicativo está em execução. Embora a nossa recomendação continue a ser a de usar um arquivo offline de aplicativo , reconhecemos que há certos cenários (por exemplo, implantações de FTP) em que não é possível.
Nesses cenários, habilite a cópia de sombra personalizando as configurações do manipulador do módulo ASP.NET Core. Na maior parte dos casos, os aplicativos ASP.NET Core não têm um web.config
adicionado ao controlo de código-fonte que você pode modificar. No ASP.NET Core, web.config
é normalmente gerado pelo SDK. A seguinte amostra web.config
pode ser usada para começar:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- To customize the asp.net core module uncomment and edit the following section.
For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->
<system.webServer>
<handlers>
<remove name="aspNetCore"/>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout">
<handlerSettings>
<handlerSetting name="experimentalEnableShadowCopy" value="true" />
<handlerSetting name="shadowCopyDirectory" value="../ShadowCopyDirectory/" />
<!-- Only enable handler logging if you encounter issues-->
<!--<handlerSetting name="debugFile" value=".\logs\aspnetcore-debug.log" />-->
<!--<handlerSetting name="debugLevel" value="FILE,TRACE" />-->
</handlerSettings>
</aspNetCore>
</system.webServer>
</configuration>
A cópia de sombra no IIS é um recurso experimental que não tem garantia de fazer parte do ASP.NET Core. Deixe comentários sobre a cópia de sombra do IIS nesta questão do GitHub em .