Share via


Prise en charge ASP.NET Core pour l’AOA natif

ASP.NET Core 8.0 introduit la prise en charge pour l’avance de temps (AOT, ahead-of-time) native .NET.

Pourquoi utiliser l’AOA natif avec ASP.NET Core

La publication et le déploiement d’une application d’AOA natif offrent les avantages suivants :

  • Empreinte disque réduite : lors de la publication à l’aide de l’AOA natif, un fichier exécutable unique est produit qui contient uniquement le code des dépendances externes utilisé pour prendre en charge le programme. Une taille d’exécutable réduite peut entraîner :
    • Des images de conteneur plus petites, par exemple dans les scénarios de déploiement conteneurisé.
    • Un temps de déploiement réduit à partir d’images plus petites.
  • Temps de démarrage réduit : les applications AOT natives peuvent présenter des temps de démarrage réduits, ce qui signifie
    • Que l’application est prête à traiter plus rapidement les requêtes.
    • Un déploiement amélioré où les orchestrateurs de conteneurs doivent gérer la transition d’une version de l’application à une autre.
  • Demande en mémoire réduite : les applications AOT natives peuvent avoir des demandes en mémoire réduites en fonction du travail effectué par l’application. Une consommation réduite de mémoire peut entraîner une plus grande densité de déploiement et une meilleure scalabilité.

L’application modèle a été exécutée dans notre laboratoire d’évaluation pour comparer les performances d’une application publiée AOT, d’une application runtime découpée et d’une application runtime non découpée. Le graphique suivant montre les résultats de l’évaluation :

Chart showing comparison of application size, memory use, and startup time metrics of an AOT published app, a runtime app that is trimmed, and an untrimmed runtime app.

Le graphique précédent montre que l’AOA natif présente des valeurs plus faibles de taille d’application, d’utilisation de mémoire et de temps de démarrage.

Compatibilité ASP.NET Core et de l’AOA natif

Toutes les fonctionnalités d’ASP.NET Core ne sont pas actuellement compatibles avec l’AOA natif. Le tableau suivant récapitule la compatibilité des fonctionnalités ASP.NET Core avec l’AOA natif :

Fonctionnalité Prise en charge intégrale Prise en charge partielle Non prise en charge
gRPC Prise en charge intégrale
API minimales Prise en charge partielle
MVC Non pris en charge
Blazor Server Non pris en charge
SignalR Non pris en charge
Authentification JWT Prise en charge intégrale
Autre authentification Non pris en charge
CORS Prise en charge intégrale
HealthChecks Prise en charge intégrale
HttpLogging Prise en charge intégrale
Localisation Prise en charge intégrale
OutputCaching Prise en charge intégrale
RateLimiting Prise en charge intégrale
RequestDecompression Prise en charge intégrale
ResponseCaching Prise en charge intégrale
ResponseCompression Prise en charge intégrale
Réécrire Prise en charge intégrale
Session Non pris en charge
Spa Non pris en charge
StaticFiles Prise en charge intégrale
WebSockets Prise en charge intégrale

Pour plus d’informations sur les limitations, consultez :

Il est important de tester soigneusement une application lors du passage à un modèle de déploiement d’AOA natif. L’application déployée AOT doit être testée pour vérifier que la fonctionnalité n’a pas changé à partir de l’application compilée juste-à-temps (JIT) et non découpée. Lors de la génération de l’application, passez en revue et corrigez les avertissements AOT. Une application qui génère des avertissements AOT pendant la publication peut ne pas fonctionner correctement. Si aucun avertissement AOT n’est émis au moment de la publication, l’application AOT publiée doit fonctionner de la même façon que l’application non tronquée compilée par JIT.

Publication AOT native

L’AOT native est activée avec la propriété MSBuild PublishAot. L’exemple suivant montre comment activer l’AOA natif dans un fichier projet :

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

Ce paramètre permet la compilation d’AOA natif pendant la publication et active l’analyse dynamique de l’utilisation du code pendant la génération et la modification. Un projet qui utilise la publication d’AOA natif utilise la compilation juste-à-temps (JIT, just in time) lors de l’exécution locale. Une application AOT présente les différences suivantes par rapport à une application compilée juste-à-temps (JIT) :

  • Certaines fonctionnalités non compatibles avec l’AOA natif sont désactivées et lèvent des exceptions au moment de l’exécution.
  • Un analyseur de source est activé pour mettre en surbrillance le code qui n’est pas compatible avec Native AOT. Au moment de la publication, la compatibilité de l’application entière, y compris les packages NuGet, est à nouveau analysée.

L’analyse d’AOT native inclut tout le code de l’application et les bibliothèques dont dépend l’application. Passez en revue les avertissements d’AOA natif et prenez des mesures correctives. Il est judicieux de publier fréquemment les applications pour détecter les problèmes au début du cycle de vie du développement.

Dans .NET 8, l’AOA natif est pris en charge par les types d’applications ASP.NET Core suivants :

Modèle d’API web (AOA natif)

Le modèle API web ASP.NET Core (AOA natif) (nom court webapiaot) crée un projet avec l’AOA activé. Le modèle diffère du modèle de projet d’API web de la manière suivante :

  • Utilise uniquement des API minimales, car MVC n’est pas encore compatible avec l’AOA natif.
  • Utilise l’API CreateSlimBuilder() pour garantir que seules les fonctionnalités essentielles sont activées par défaut, ce qui réduit la taille déployée de l’application.
  • Est configuré pour écouter uniquement sur HTTP, car le trafic HTTPS est généralement géré par un service d’entrée dans les déploiements natifs cloud.
  • N’inclut pas de profil de lancement pour l’exécution sous IIS ou IIS Express.
  • Crée un fichier .http configuré avec des exemples de requêtes HTTP qui peuvent être envoyées aux points de terminaison de l’application.
  • Inclut un exemple d’API Todo au lieu de l’exemple de prévision météorologique.
  • Ajoute PublishAot au fichier projet, comme indiqué précédemment dans cet article.
  • Active les générateurs de source du sérialiseur JSON. Le générateur de source est utilisé pour générer du code de sérialisation au moment de la génération, ce qui est requis pour la compilation de l’AOA natif.

Modifications nécessaires à la prise en charge de la génération de source

L’exemple suivant montre le code ajouté au fichier Program.cs pour prendre en charge la génération de source de sérialisation 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
+{
+
+}

Sans ce code ajouté, System.Text.Json utilise la réflexion pour sérialiser et désérialiser JSON. La réflexion n’est pas prise en charge dans l’AOA natif.

Pour en savoir plus, consultez :

Modifications apportées à launchSettings.json

Le fichier launchSettings.json créé par le modèle API web (AOA natif) ne contient pas la section iisSettings et le profil IIS Express :

{
  "$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"
-      }
-    }
  }
}

Méthode CreateSlimBuilder

Le modèle utilise la méthode CreateSlimBuilder() au lieu de la méthode 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
{

}

La méthode CreateSlimBuilder initialise le WebApplicationBuilder avec les fonctionnalités ASP.NET Core minimales nécessaires à l’exécution d’une application.

Comme indiqué précédemment, la méthode CreateSlimBuilder n’inclut pas la prise en charge du protocole HTTPS ou HTTP/3. Ces protocoles ne sont généralement pas requis pour les applications qui s’exécutent derrière un proxy de terminaison TLS. Par exemple, consultez Terminaison TLS et TLS de bout en bout avec Application Gateway. HTTPS peut être activé en appelant builder.WebHost.UseKestrelHttpsConfiguration HTTP/3 peut être activé en appelant builder.WebHost.UseQuic.

Comparaison de CreateSlimBuilder et de CreateBuilder

La méthode CreateSlimBuilder ne prend pas en charge les fonctionnalités suivantes prises en charge par la méthode CreateBuilder :

La méthode CreateSlimBuilder comprend les fonctionnalités suivantes nécessaires à une expérience de développement efficace :

  • JSConfiguration du fichier ON pour appsettings.json et appsettings.{EnvironmentName}.json.
  • Configuration des secrets utilisateur.
  • Journalisation de la console.
  • Configuration de la journalisation.

Pour un générateur qui omet les fonctionnalités précédentes, consultez la méthode CreateEmptyBuilder.

L’inclusion de fonctionnalités minimales présente des avantages pour le découpage ainsi que pour l’AOT. Pour plus d’informations, consultez Découper les déploiements autonomes et les exécutables.

Pour plus d’informations, consultez Comparaison de WebApplication.CreateBuilder à CreateSlimBuilder

Générateurs de source

Étant donné que le code inutilisé est découpé lors de la publication pour l’AOA natif, l’application ne peut pas utiliser la réflexion illimitée au moment du runtime. Les générateurs de sources sont utilisés pour produire du code afin d’éviter la réflexion. Dans certains cas, les générateurs de sources produisent du code optimisé pour l’AOT, même lorsqu’un générateur n’est pas requis.

Pour afficher le code source généré, ajoutez la propriété EmitCompilerGeneratedFiles au fichier .csproj d’une application, comme illustré dans l’exemple suivant :

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

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

</Project>

Exécutez la commande dotnet build pour afficher le code généré. La sortie inclut un répertoire obj/Debug/net8.0/generated/ qui contient tous les fichiers générés pour le projet.

La commande dotnet publish compile également les fichiers sources et génère des fichiers compilés. En outre, dotnet publish transmet les assemblys générés à un compilateur IL natif. Le compilateur IL produit l’exécutable natif. L’exécutable natif contient le code de l’ordinateur natif.

Bibliothèques et AOA natif

La plupart des bibliothèques populaires utilisées dans les projets ASP.NET Core présentent actuellement des problèmes de compatibilité lorsqu’elles sont utilisées dans un projet ciblant l’AOA natif, par exemple :

  • Utilisation de la réflexion pour inspecter et découvrir des types.
  • Chargement conditionnel de bibliothèques au moment de l’exécution.
  • Génération de code à la volée pour implémenter des fonctionnalités.

Les bibliothèques qui utilisent ces fonctionnalités dynamiques doivent être mises à jour pour fonctionner avec l’AOA natif. Elles peuvent être mises à jour à l’aide d’outils tels que les générateurs de sources Roslyn.

Les auteurs de bibliothèques qui espèrent prendre en charge l’AOA natif sont invités à :

API minimales et charges utiles JSON

L’infrastructure d’API minimales est optimisée pour recevoir et retourner des charges utiles JSON à l’aide de System.Text.Json. System.Text.Json:

Tous les types transmis dans le corps HTTP ou retournés par les délégués de requête dans les applications API minimales doivent être configurés sur un JsonSerializerContext inscrit via l’injection de dépendances d’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
{

}

Dans le code en surbrillance précédent :

Paramètre sur le délégué qui n’est pas lié au corps et n’a pas besoin d’être sérialisable. Par exemple, un paramètre de chaîne de requête qui est un type d’objet enrichi et implémente 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.

Problèmes connus

Consultez ce problème GitHub pour signaler ou examiner les problèmes liés à la prise en charge de l’AOA natif dans ASP.NET Core.

Voir aussi