Suporte do ASP.NET Core ao AOT nativo

Por Mitch Denny

Publicar e implantar aplicativos AOT (nativos com antecedência) no ASP.NET Core oferece vários benefícios:

  • Volume de disco minimizado. Quando você publica um aplicativo usando o AOT Nativo, o processo produz um único arquivo executável. O executável contém apenas o código das dependências externas necessárias para dar suporte ao aplicativo. O tamanho executável reduzido pode levar a:

    • Imagens de contêiner menores, por exemplo, em cenários de implantação em contêineres.
    • Reduzido o tempo de implantação graças a imagens menores.
  • Tempo de inicialização reduzido. Aplicativos AOT nativos podem exigir menos tempo de inicialização, o que permite:

    • O aplicativo para processar solicitações mais rapidamente.
    • Implantação aprimorada, em que os orquestradores de contêiner gerenciam a transição de uma versão de aplicativo para outra.
  • Redução da demanda de memória. Aplicativos AOT nativos podem exigir menos memória, dependendo do trabalho feito pelo aplicativo. A redução do consumo de memória pode levar a maior densidade de implantação e escalabilidade aprimorada.

O gráfico a seguir mostra os resultados de um teste de benchmarking nos vários aplicativos de modelo. O benchmark compara o desempenho de um aplicativo publicado por AOT (barra laranja), um aplicativo com runtime reduzido (barra verde) e um aplicativo com runtime não reduzido (barra amarela). O teste revelou que o aplicativo AOT nativo demonstra menor tamanho do aplicativo, uso de memória e tempo de inicialização.

Gráfico mostrando uma comparação do tamanho do aplicativo, do uso da memória e das métricas de tempo de inicialização. O gráfico compara um aplicativo AOT nativo publicado, um aplicativo de runtime cortado e um aplicativo de runtime não recortado.

Este artigo descreve o suporte para aplicativos AOT nativos em ASP.NET Core, incluindo uma visão geral da publicação e implantação.

Para obter orientações sobre AOT nativo do Blazor WebAssembly ASP.NET Core, que complementam ou substituem as orientações deste artigo, consulte Ferramentas de compilação do ASP.NET Core Blazor WebAssembly e compilação antecipada (AOT, Ahead-Of-Time).

Revisar a compatibilidade do ASP.NET Core e AOT Nativo

Atualmente, nem todos os recursos do ASP.NET Core são compatíveis com o AOT nativo.

A seguinte tabela resume a compatibilidade de recursos do ASP.NET Core com o AOT nativo:

Recurso Suportado Suporte parcial Sem suporte
Blazor Server
CORS ✔️
gRPC ✔️
HealthChecks ✔️
HttpLogging ✔️
Autenticação JWT ✔️
Localização ✔️
APIs mínimas ✔️
MVC
Outra autenticação
OutputCaching ✔️
RateLimiting ✔️
SolicitarDescompressão ✔️
Cache de Respostas ✔️
Compressão de Resposta ✔️
Rewrite ✔️
Sessão
SignalR ✔️
Spa
StaticFiles ✔️
WebSockets ✔️

Para obter mais informações sobre limitações, consulte:

Verificar o aplicativo no modelo de implantação do AOT nativo

É importante testar um aplicativo minuciosamente quando você passa para um modelo de implantação AOT nativo. Teste o aplicativo implantado via AOT e confirme se a funcionalidade permanece inalterada em relação ao aplicativo compilado sem otimizações e sob demanda (JIT, Just-In-Time).

Ao criar o aplicativo, revise e corrija quaisquer avisos do AOT. Um aplicativo que emite avisos AOT durante a publicação pode não funcionar corretamente. Se nenhum aviso do AOT for emitido no momento da publicação, você pode esperar que o aplicativo AOT publicado funcione da mesma forma que o aplicativo não otimizado e compilado JIT.

Publicar um aplicativo AOT nativo (PublishAot)

Habilite o AOT nativo para seu aplicativo usando a PublishAot propriedade MSBuild. O seguinte exemplo mostra como habilitar o AOT nativo em um arquivo de projeto:

<PropertyGroup>
  <PublishAot>true</PublishAot>
</PropertyGroup>

A PublishAot propriedade habilita a compilação AOT nativa durante o processo de publicação e habilita a análise dinâmica de uso de código durante a compilação e edição. Um projeto que usa a publicação AOT nativa implementa a compilação JIT quando ele é executado localmente.

Um aplicativo AOT tem as seguintes diferenças em relação a um aplicativo de compilação JIT:

  • Os recursos que não são compatíveis com o AOT nativo são desabilitados e geram exceções em runtime.
  • Um analisador de origem está habilitado para realçar o código que não é compatível com o AOT nativo. No momento da publicação, todo o aplicativo, incluindo pacotes NuGet, é analisado para compatibilidade novamente.

A análise AOT nativa inclui todo o código do aplicativo e as bibliotecas das quais o aplicativo depende. Leia os avisos do AOT nativo e realize as etapas corretivas. É uma boa ideia publicar aplicativos com frequência para descobrir problemas no início do ciclo de vida de desenvolvimento.

No .NET 8 e posterior, os seguintes tipos de aplicativo ASP.NET Core dão suporte ao AOT Nativo:

Examinar o modelo de API Web (AOT Nativo)

O modelo ASP.NET Core Web API (Native AOT) (nome curto webapiaot) cria um projeto com a AOT habilitada. O modelo difere de um modelo de projeto de API Web padrão das seguintes maneiras:

  • Usa somente APIs mínimas, pois o MVC ainda não é compatível com o AOT nativo.
  • Usa a CreateSlimBuilder() API para garantir que apenas os recursos essenciais sejam habilitados por padrão, o que minimiza o tamanho implantado do aplicativo.
  • Está configurado para escutar somente em HTTP. O tráfego HTTPS geralmente é tratado por um serviço de entrada em implantações nativas de nuvem.
  • Não inclui um perfil de inicialização para execução no IIS ou no IIS Express.
  • Cria um arquivo .http configurado com solicitações HTTP de exemplo que podem ser enviadas para os pontos de extremidade do aplicativo.
  • Inclui uma amostra de API Todo em vez da amostra de previsão do tempo.
  • Adiciona a PublishAot propriedade ao arquivo de projeto, conforme descrito anteriormente.
  • Habilita os geradores de origem do serializador JSON. O gerador de origem é utilizado para produzir o código de serialização durante o build, o que é necessário para a compilação AOT nativa.

Atualizações de código para serialização JSON (Program.cs)

O código no arquivo Program.cs é modificado para fornecer suporte para a geração de origem de serialização JSON.

O snippet a seguir mostra as alterações no código:

using MyFirstAotWebApi;
+using System.Text.Json.Serialization;

-var builder = WebApplication.CreateBuilder();
+var builder = WebApplication.CreateSlimBuilder(args);

+builder.Services.ConfigureHttpJsonOptions(options =>
+{
+  options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
+});

var app = builder.Build();

var sampleTodos = TodoGenerator.GenerateTodos().ToArray();

var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos);
todosApi.MapGet("/{id}", (int id) =>
    sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
        ? Results.Ok(todo)
        : Results.NotFound());

app.Run();

+[JsonSerializable(typeof(Todo[]))]
+internal partial class AppJsonSerializerContext : JsonSerializerContext
+{
+
+}

Se você não modificar o código, System.Text.Json usará reflexão para serializar e desserializar JSON. Não há suporte para reflexão no AOT nativo.

Para saber mais, veja:

Alterações de código para o perfil de inicialização (launchSettings.json)

O modelo de API Web (AOT Nativo) cria um arquivo launchSettings.json . Ao contrário de um arquivo de inicialização padrão, o arquivo gerado não inclui a iisSettings seção ou o IIS Express perfil.

O trecho a seguir mostra as seções excluídas, destacadas em vermelho:

{
  "$schema": "http://json.schemastore.org/launchsettings.json",
-  "iisSettings": {
-     "windowsAuthentication": false,
-     "anonymousAuthentication": true,
-     "iisExpress": {
-       "applicationUrl": "http://localhost:11152",
-       "sslPort": 0
-     }
-   },
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "todos",
      "applicationUrl": "http://localhost:5102",
        "environmentVariables": {
          "ASPNETCORE_ENVIRONMENT": "Development"
        }
      },
-     "IIS Express": {
-       "commandName": "IISExpress",
-       "launchBrowser": true,
-       "launchUrl": "todos",
-      "environmentVariables": {
-       "ASPNETCORE_ENVIRONMENT": "Development"
-      }
-    }
  }
}

CreateSlimBuilder() chamado para as configurações mínimas de aplicativo

O modelo de API Web (AOT Nativo) usa o CreateSlimBuilder() método em vez do CreateBuilder() método.

using System.Text.Json.Serialization;
using MyFirstAotWebApi;

var builder = WebApplication.CreateSlimBuilder(args);
builder.Logging.AddConsole();

builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});

var app = builder.Build();

var sampleTodos = TodoGenerator.GenerateTodos().ToArray();

var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos);
todosApi.MapGet("/{id}", (int id) =>
    sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
        ? Results.Ok(todo)
        : Results.NotFound());

app.Run();

[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}

O método CreateSlimBuilder inicializa o WebApplicationBuilder com os recursos mínimos do ASP.NET Core necessários para executar um aplicativo.

Conforme descrito anteriormente, o CreateSlimBuilder método não inclui suporte para HTTPS ou HTTP/3. Normalmente, esses protocolos não são necessários para aplicativos executados por trás de um proxy de terminação TLS. Por exemplo, veja a Terminação TLS e TLS de ponta a ponta com o Gateway de Aplicativo. Você pode habilitar HTTPS chamando o método builder.WebHost.UseKestrelHttpsConfiguration, ou habilitar HTTP/3 chamando o método builder.WebHost.UseQuic.

Comparar CreateSlimBuilder() e CreateBuilder()

O CreateSlimBuilder método fornece acesso a uma parte dos recursos do aplicativo disponíveis com o CreateBuilder método. Conforme descrito anteriormente, o modelo Web API (Native AOT) chama CreateSlimBuilder para inicializar WebApplicationBuilder, de modo que o construtor usa os recursos mínimos de ASP.NET Core necessários para executar o aplicativo.

Ambos os métodos fornecem os recursos necessários para uma experiência de desenvolvimento eficiente:

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

A inclusão de recursos mínimos tem benefícios para filtragem, bem como AOT. Para obter mais informações, confira Cortar implantações e executáveis autocontidos.

Se você preferir usar um construtor que omita todos os recursos, consulte o método WebApplication.CreateEmptyBuilder .

Recursos indisponíveis no CreateSlimBuilder

O CreateSlimBuilder método não fornece os seguintes recursos, que estão disponíveis em CreateBuilder:

Para obter informações mais detalhadas, consulte Comparing WebApplication.CreateBuilder to CreateSlimBuilder

Usar geradores de código-fonte e evitar reflexão

Durante o processo de publicação do AOT Nativo, qualquer código não utilizado é cortado. Como resultado, um aplicativo não pode usar reflexão não limitada em tempo de execução. Você pode usar geradores de origem que produzem código que evita a necessidade de reflexão. Em alguns casos, o código de saída dos geradores de origem é otimizado para AOT mesmo quando um gerador não é necessário.

  • Para exibir o código-fonte gerado, adicione a propriedade EmitCompilerGeneratedFiles ao arquivo do projeto de aplicativo (.csproj):

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
       <PropertyGroup>
         <!-- Other properties omitted for brevity -->
         <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
       </PropertyGroup>
    
    </Project>
    
  • Para ver o código gerado, execute o dotnet build comando. O comando compila os arquivos de origem e gera os arquivos intermediários necessários para executar o aplicativo em um ambiente de desenvolvimento. A saída inclui um diretório obj/Debug/<.NET>/generated/ que contém todos os arquivos gerados para o projeto.

  • Para preparar o aplicativo para implantação, execute o dotnet publish comando. O comando compila os arquivos de origem e gera todos os arquivos necessários para implantar o aplicativo. Ele passa os assemblies gerados para um compilador il nativo, que produz o executável nativo. O executável nativo contém o código do computador nativo.

Usar bibliotecas com a AOT nativa

Muitas bibliotecas populares usadas em projetos ASP.NET Core atualmente têm alguns problemas de compatibilidade quando são incorporadas em projetos direcionados ao AOT Nativo, como:

  • Usando reflexão para inspecionar e descobrir tipos
  • Carregando bibliotecas condicionalmente em tempo de execução
  • Gerando código em tempo real para implementar a funcionalidade

As bibliotecas que usam esses recursos dinâmicos exigem atualizações para funcionar com o AOT nativo. Várias ferramentas estão disponíveis para aplicar as atualizações necessárias, como geradores de origem Roslyn.

Os autores da biblioteca que desejam dar suporte ao AOT Nativo são incentivados a revisar os seguintes artigos:

Trabalhar com APIs mínimas e cargas JSON

A estrutura de API Mínima é otimizada para receber e retornar cargas JSON usando o System.Text.Json.

  • O namespace impõe requisitos de compatibilidade para JSON e AOT nativo.
  • Ele requer o uso do gerador de código-fonte System.Text.Json.

Todos os tipos transmitidos como parte do corpo HTTP ou retornados por delegados de solicitação em aplicativos de APIs mínimas devem ser configurados em uma instância JsonSerializerContext. A instância deve ser registrada com a injeção de dependência do ASP.NET Core:

using System.Text.Json.Serialization;
using MyFirstAotWebApi;

var builder = WebApplication.CreateSlimBuilder(args);
builder.Logging.AddConsole();

builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});

var app = builder.Build();

var sampleTodos = TodoGenerator.GenerateTodos().ToArray();

var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos);
todosApi.MapGet("/{id}", (int id) =>
    sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
        ? Results.Ok(todo)
        : Results.NotFound());

app.Run();

[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}

Um parâmetro no delegado que não está associado ao corpo não precisa ser serializável. Por exemplo, um parâmetro de cadeia de caracteres de consulta pode ser um tipo de objeto avançado que implementa IParsable<T>.

public class Todo
{
    public int Id { get; set; }
    public string? Title { get; set; }
    public DateOnly? DueBy { get; set; }
    public bool IsComplete { get; set; }
}

static class TodoGenerator
{
    private static readonly (string[] Prefixes, string[] Suffixes)[] _parts = new[]
        {
            (new[] { "Walk the", "Feed the" }, new[] { "dog", "cat", "goat" }),
            (new[] { "Do the", "Put away the" }, new[] { "groceries", "dishes", "laundry" }),
            (new[] { "Clean the" }, new[] { "bathroom", "pool", "blinds", "car" })
        };
    // Remaining code omitted for brevity.

Examine os problemas conhecidos

Para relatar ou examinar problemas com o suporte do AOT nativo em ASP.NET Core, consulte GitHub /dotnet/core/issues #8288).

O ASP.NET Core 8 é compatível com AOT (ahead-of-time) nativo do .NET.

Razões para usar o AOT nativo com o ASP.NET Core

Publicar e implantar um aplicativo AOT nativo oferece os seguintes benefícios:

  • Volume de disco minimizado: com a publicação por meio do AOT nativo, é produzido um só executável contendo apenas o código de dependências externas necessário para dar suporte ao programa. O tamanho do executável reduzido pode levar a:
    • Imagens de contêiner menores, por exemplo, em cenários de implantação em contêineres.
    • Reduzido o tempo de implantação graças a imagens menores.
  • Tempo de inicialização reduzido: os aplicativos AOT nativos podem mostrar tempos de inicialização reduzidos, o que significa
    • O aplicativo está pronto para atender solicitações mais rapidamente.
    • Implantação aprimorada em que os orquestradores de contêineres precisam gerenciar a transição de uma versão do aplicativo para outra.
  • Demanda de memória reduzida: os aplicativos AOT nativos podem ter demandas de memória reduzidas, dependendo do trabalho executado pelo aplicativo. A redução do consumo de memória pode levar a maior densidade de implantação e escalabilidade aprimorada.

O aplicativo modelo foi executado em nosso laboratório de benchmarking para comparar o desempenho de um aplicativo publicado pelo AOT, um aplicativo de runtime filtrado e um aplicativo de runtime não filtrado. O gráfico a seguir mostra os resultados do benchmarking:

Gráfico mostrando a comparação das métricas de tamanho do aplicativo, uso de memória e tempo de inicialização de um aplicativo publicado no AOT, de um aplicativo de runtime que foi ajustado e de um aplicativo de runtime não ajustado.

O gráfico anterior mostra que o AOT nativo tem tamanho de aplicativo, uso de memória e tempo de inicialização menores.

Compatibilidade entre o ASP.NET Core e o AOT nativo

Atualmente, nem todos os recursos do ASP.NET Core são compatíveis com o AOT nativo. A seguinte tabela resume a compatibilidade de recursos do ASP.NET Core com o AOT nativo:

Recurso Totalmente compatível Suporte parcial Sem suporte
gRPC Totalmente suportado
APIs mínimas Parcialmente compatível
MVC Sem suporte
Blazor Server Sem suporte
SignalR Sem suporte
Autenticação JWT Totalmente suportado
Outra autenticação Sem suporte
CORS Totalmente suportado
HealthChecks Totalmente suportado
HttpLogging Totalmente suportado
Localização Totalmente suportado
OutputCaching Totalmente suportado
RateLimiting Totalmente suportado
SolicitarDescompressão Totalmente suportado
Cache de Respostas Totalmente suportado
Compressão de Resposta Totalmente suportado
Rewrite Totalmente suportado
Sessão Sem suporte
Spa Sem suporte
StaticFiles Totalmente suportado
WebSockets Totalmente suportado

Para obter mais informações sobre limitações, consulte:

É importante testar um aplicativo minuciosamente ao migrar para um modelo de implantação AOT nativo. O aplicativo AOT implantado deve ser testado para verificar se a funcionalidade não foi alterada em relação ao aplicativo não filtrado e de compilação JIT. ** Durante a construção do aplicativo, revise e corrija os avisos AOT. Um aplicativo que emite avisos AOT durante a publicação pode não funcionar corretamente. Se nenhum aviso AOT for emitido no momento da publicação, o aplicativo AOT publicado deverá funcionar da mesma forma que o aplicativo compilado por untrimmed e JIT.

Publicação do AOT nativo

O AOT nativo está habilitado com a propriedade MSBuild PublishAot. O seguinte exemplo mostra como habilitar o AOT nativo em um arquivo de projeto:

<PropertyGroup>
  <PublishAot>true</PublishAot>
</PropertyGroup>

Essa configuração habilita a compilação AOT nativo durante a publicação e a análise dinâmica de uso de código durante o build e a edição. Um projeto que usa a publicação AOT nativo usa a compilação JIT ao ser executado localmente. Um aplicativo AOT tem as seguintes diferenças em relação a um aplicativo de compilação JIT:

  • Os recursos que não são compatíveis com o AOT nativo são desabilitados e geram exceções em runtime.
  • Um analisador de origem está habilitado para realçar o código que não é compatível com o AOT nativo. No momento da publicação, todo o aplicativo, incluindo pacotes NuGet, é analisado para compatibilidade novamente.

A análise AOT nativa inclui todo o código do aplicativo e as bibliotecas das quais o aplicativo depende. Leia os avisos do AOT nativo e realize as etapas corretivas. É uma boa ideia publicar aplicativos com frequência para descobrir problemas no início do ciclo de vida de desenvolvimento.

No .NET 8, o AOT nativo é compatível com os seguintes tipos de aplicativos ASP.NET Core:

O modelo de API Web (AOT nativo)

O modelo de API Web do ASP.NET Core (cujo nome curto é webapiaot) cria um projeto com o AOT habilitado. O modelo difere do modelo de projeto da API Web das seguintes maneiras:

  • Usa somente APIs mínimas, pois o MVC ainda não é compatível com o AOT nativo.
  • Usa a API CreateSlimBuilder() para garantir que apenas os recursos essenciais sejam habilitados por padrão, minimizando o tamanho implantado do aplicativo.
  • É configurado para escutar somente HTTP, pois o tráfego HTTPS geralmente é tratado por um serviço de entrada em implantações nativas de nuvem.
  • Não inclui um perfil de inicialização para execução no IIS ou no IIS Express.
  • Cria um arquivo .http configurado com exemplos de solicitações HTTP que podem ser enviadas para os endpoints do aplicativo.
  • Inclui uma amostra de API Todo em vez da amostra de previsão do tempo.
  • Adiciona PublishAot ao arquivo de projeto, conforme mostrado anteriormente neste artigo.
  • Habilita os geradores de origem do serializador JSON. O gerador de origem é utilizado para produzir o código de serialização durante o build, o que é necessário para a compilação AOT nativa.

Alterações para dar suporte à geração de código-fonte

O exemplo a seguir mostra o código adicionado ao arquivo Program.cs para dar suporte à geração de origem de serialização JSON:

using MyFirstAotWebApi;
+using System.Text.Json.Serialization;

-var builder = WebApplication.CreateBuilder();
+var builder = WebApplication.CreateSlimBuilder(args);

+builder.Services.ConfigureHttpJsonOptions(options =>
+{
+  options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
+});

var app = builder.Build();

var sampleTodos = TodoGenerator.GenerateTodos().ToArray();

var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos);
todosApi.MapGet("/{id}", (int id) =>
    sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
        ? Results.Ok(todo)
        : Results.NotFound());

app.Run();

+[JsonSerializable(typeof(Todo[]))]
+internal partial class AppJsonSerializerContext : JsonSerializerContext
+{
+
+}

Sem esse código adicionado, System.Text.Json usa a reflexão para serializar e desserializar o JSON. Não há suporte para reflexão no AOT nativo.

Para saber mais, veja:

Alterações para launchSettings.json

O arquivo launchSettings.json criado pelo modelo de API Web (AOT nativo) tem a seção iisSettings e o perfil IIS Express removidos:

{
  "$schema": "http://json.schemastore.org/launchsettings.json",
-  "iisSettings": {
-     "windowsAuthentication": false,
-     "anonymousAuthentication": true,
-     "iisExpress": {
-       "applicationUrl": "http://localhost:11152",
-       "sslPort": 0
-     }
-   },
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "todos",
      "applicationUrl": "http://localhost:5102",
        "environmentVariables": {
          "ASPNETCORE_ENVIRONMENT": "Development"
        }
      },
-     "IIS Express": {
-       "commandName": "IISExpress",
-       "launchBrowser": true,
-       "launchUrl": "todos",
-      "environmentVariables": {
-       "ASPNETCORE_ENVIRONMENT": "Development"
-      }
-    }
  }
}

O método CreateSlimBuilder

O modelo usa o método CreateSlimBuilder() em vez do método CreateBuilder().

using System.Text.Json.Serialization;
using MyFirstAotWebApi;

var builder = WebApplication.CreateSlimBuilder(args);
builder.Logging.AddConsole();

builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});

var app = builder.Build();

var sampleTodos = TodoGenerator.GenerateTodos().ToArray();

var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos);
todosApi.MapGet("/{id}", (int id) =>
    sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
        ? Results.Ok(todo)
        : Results.NotFound());

app.Run();

[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}

O método CreateSlimBuilder inicializa o WebApplicationBuilder com os recursos mínimos do ASP.NET Core necessários para executar um aplicativo.

Conforme observado anteriormente, o método CreateSlimBuilder não é compatível com HTTPS ou HTTP/3. Normalmente, esses protocolos não são necessários para aplicativos executados por trás de um proxy de terminação TLS. Por exemplo, veja a Terminação TLS e TLS de ponta a ponta com o Gateway de Aplicativo. O HTTPS pode ser habilitado chamando builder.WebHost.UseKestrelHttpsConfiguration. HTTP/3 pode ser habilitado chamando builder.WebHost.UseQuic.

CreateSlimBuilder versus CreateBuilder

O método CreateSlimBuilder não dá suporte aos seguintes recursos que têm suporte pelo método CreateBuilder:

O método CreateSlimBuilder inclui os seguintes recursos 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.
  • Registro em log de console.
  • Configuração do registro em log.

Para um construtor que omite os recursos acima, consulte O método CreateEmptyBuilder.

A inclusão de recursos mínimos tem benefícios para filtragem, bem como AOT. Para obter mais informações, confira Cortar implantações e executáveis autocontidos.

Para obter informações mais detalhadas, consulte Comparando WebApplication.CreateBuilder com CreateSlimBuilder

Geradores de origem

Como o código não utilizado é cortado durante a publicação para o Native AOT, o aplicativo não pode usar a reflexão irrestrita em tempo de execução. Os geradores de origem são usados para produzir código que evita a necessidade de reflexão. Em alguns casos, os geradores de origem produzem código otimizado para AOT mesmo quando um gerador não é necessário.

Para exibir o código-fonte gerado, adicione a propriedade EmitCompilerGeneratedFiles ao arquivo .csproj de um aplicativo, conforme mostrado no exemplo a seguir:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <!-- Other properties omitted for brevity -->
    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
  </PropertyGroup>

</Project>

Execute o comando dotnet build para ver o código gerado. A saída inclui um diretório obj/Debug/net8.0/generated/ que contém todos os arquivos gerados para o projeto.

O comando dotnet publish também compila os arquivos de origem e gera arquivos compilados. Além disso, dotnet publish passa os assemblies gerados para um compilador de IL nativo. O compilador de IL produz o executável nativo. O executável nativo contém o código do computador nativo.

Usar bibliotecas com a AOT nativa

Muitas bibliotecas populares usadas em projetos ASP.NET Core atualmente têm alguns problemas de compatibilidade quando são incorporadas em projetos direcionados ao AOT Nativo, como:

  • Usando reflexão para inspecionar e descobrir tipos
  • Carregando bibliotecas condicionalmente em tempo de execução
  • Gerando código em tempo real para implementar a funcionalidade

As bibliotecas que usam esses recursos dinâmicos exigem atualizações para funcionar com o AOT nativo. Várias ferramentas estão disponíveis para aplicar as atualizações necessárias, como geradores de origem Roslyn.

Os autores da biblioteca que desejam dar suporte ao AOT Nativo são incentivados a revisar os seguintes artigos:

APIs mínimas e cargas JSON

A estrutura de API Mínima é otimizada para receber e retornar cargas JSON usando System.Text.Json. System.Text.Json:

Todos os tipos transmitidos como parte do corpo HTTP ou retornados de representantes de solicitação em aplicativos de APIs Mínimas devem ser configurados em um JsonSerializerContext registrado por meio da injeção de dependência do ASP.NET Core:

using System.Text.Json.Serialization;
using MyFirstAotWebApi;

var builder = WebApplication.CreateSlimBuilder(args);
builder.Logging.AddConsole();

builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});

var app = builder.Build();

var sampleTodos = TodoGenerator.GenerateTodos().ToArray();

var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos);
todosApi.MapGet("/{id}", (int id) =>
    sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
        ? Results.Ok(todo)
        : Results.NotFound());

app.Run();

[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}

No código realçado anterior:

Um parâmetro no delegado que não está associado ao corpo e não precisa ser serializável. Por exemplo, um parâmetro de cadeia de caracteres de consulta que é um tipo de objeto avançado e implementa IParsable<T>.

public class Todo
{
    public int Id { get; set; }
    public string? Title { get; set; }
    public DateOnly? DueBy { get; set; }
    public bool IsComplete { get; set; }
}

static class TodoGenerator
{
    private static readonly (string[] Prefixes, string[] Suffixes)[] _parts = new[]
        {
            (new[] { "Walk the", "Feed the" }, new[] { "dog", "cat", "goat" }),
            (new[] { "Do the", "Put away the" }, new[] { "groceries", "dishes", "laundry" }),
            (new[] { "Clean the" }, new[] { "bathroom", "pool", "blinds", "car" })
        };
    // Remaining code omitted for brevity.

Problemas conhecidos

Confira este problema do GitHub para relatar ou analisar problemas com o suporte do AOT nativo no ASP.NET Core.

Veja também