ASP.NET Core-Unterstützung für native AOT-Kompilierung

In ASP.NET Core 8.0 wird Unterstützung für native .NET-AOT-Kompilierung (Ahead-Of-Time) eingeführt.

Gründe für die Verwendung von nativer AOT-Kompilierung mit ASP.NET Core

Das Veröffentlichen und Bereitstellen einer nativen AOT-App bietet die folgenden Vorteile:

  • Minimierter benötigter Speicherplatz auf dem Datenträger: Bei der Veröffentlichung mit nativer AOT-Kompilierung wird eine einzelne ausführbare Datei erstellt, die nur den Code aus externen Abhängigkeiten enthält, der zur Unterstützung des Programms erforderlich ist. Die reduzierte Größe ausführbarer Dateien kann zu Folgendem führen:
    • Kleinere Containerimages, z. B. in Containerbereitstellungsszenarien
    • Kürzere Bereitstellungsdauer durch kleinere Images
  • Verkürzte Startzeit: Native AOT-Anwendungen können kürzere Startzeiten aufweisen. Dies bedeutet
    • Die App kann Anforderungen schneller verarbeiten.
    • Verbesserte Bereitstellung, bei der Containerorchestratoren den Übergang von einer Version der App zu einer anderen verwalten müssen
  • Reduzierter Speicherbedarf: Native AOT-Apps können je nach den von der App ausgeführten Aktionen einen geringeren Speicherbedarf aufweisen. Eine reduzierte Arbeitsspeichernutzung kann zu einer höheren Bereitstellungsdichte und besserer Skalierbarkeit führen.

Die Vorlagen-App wurde in unserem Benchmark-Lab ausgeführt, um die Leistung einer mit AOT-Kompilierung veröffentlichten App, einer gekürzten Runtime-App und einer nicht gekürzten Runtime-App zu vergleichen. Die folgende Abbildung zeigt die Ergebnisse des Benchmarkings:

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.

Die Abbildung oben zeigt, dass native AOT-Kompilierung eine geringere App-Größe, Arbeitsspeicherauslastung und Startzeit aufweist.

Kompatibilität von ASP.NET Core und nativer AOT-Kompilierung

Nicht alle Features in ASP.NET Core sind derzeit mit nativer AOT-Kompilierung kompatibel. In der folgenden Tabelle ist die Kompatibilität von ASP.NET Core-Features mit nativer AOT-Kompilierung zusammengefasst:

Funktion Vollständig unterstützt Teilweise unterstützt Nicht unterstützt
gRPC Vollständig unterstützt
Minimale APIs Teilweise unterstützt
MVC Nicht unterstützt
Blazor Server Nicht unterstützt
SignalR Nicht unterstützt
JWT-Authentifizierung Vollständig unterstützt
Andere Authentifizierung Nicht unterstützt
CORS Vollständig unterstützt
HealthChecks Vollständig unterstützt
HttpLogging Vollständig unterstützt
Lokalisierung Vollständig unterstützt
OutputCaching Vollständig unterstützt
RateLimiting Vollständig unterstützt
RequestDecompression Vollständig unterstützt
ResponseCaching Vollständig unterstützt
ResponseCompression Vollständig unterstützt
Rewrite Vollständig unterstützt
Sitzung Nicht unterstützt
Spa Nicht unterstützt
StaticFiles Vollständig unterstützt
WebSockets Vollständig unterstützt

Weitere Informationen zu Beschränkungen finden Sie unter:

Es ist wichtig, eine App gründlich zu testen, wenn Sie zu einem nativen AOT-Bereitstellungsmodell wechseln. Die über die AOT bereitgestellte App sollte getestet werden, um sicherzustellen, dass sich die Funktionalität im Vergleich zur nicht gekürzten und mit JIT kompilierten App nicht geändert hat. Überprüfen und korrigieren Sie AOT-Warnungen beim Erstellen der App. Eine App, die während der Veröffentlichung AOT-Warnungen erzeugt, funktioniert möglicherweise nicht ordnungsgemäß. Wenn zur Veröffentlichungszeit keine AOT-Warnungen ausgegeben werden, sollte die veröffentlichte AOT-App genauso funktionieren wie die ungetrimmte und JIT-kompilierte App.

Native AOT-Veröffentlichung

Native AOT-Kompilierung wird mit der MSBuild-Eigenschaft PublishAot aktiviert. Das folgende Beispiel zeigt, wie systemeigene AOT-Kompilierung in einer Projektdatei aktiviert wird:

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

Diese Einstellung aktiviert native AOT-Kompilierung während der Veröffentlichung und dynamische Analyse der Codeverwendung während des Build- und Bearbeitungsvorgangs. Ein Projekt, das die native AOT-Veröffentlichung verwendet, nutzt bei lokaler Ausführung die JIT-Kompilierung. Eine AOT-App weist die folgenden Unterschiede zu einer JIT-kompilierten App auf:

  • Nicht mit nativer AOT-Kompilierung kompatible Features sind deaktiviert und lösen zur Laufzeit Ausnahmen aus.
  • Ein Quellanalysetool ist aktiviert, um Code hervorzuheben, der nicht mit nativer AOT-Kompilierung kompatibel ist. Zum Zeitpunkt der Veröffentlichung wird die gesamte App, einschließlich NuGet-Paketen, erneut auf Kompatibilität analysiert.

Die Analyse der nativen AOT-Kompilierung umfasst den gesamten Code der App und die Bibliotheken, von der die App abhängig ist. Überprüfen Sie Warnungen der nativen AOT-Kompilierung und führen Sie Korrekturschritte durch. Es ist ratsam, Apps häufig zu veröffentlichen, um Probleme frühzeitig im Entwicklungslebenszyklus zu erkennen.

In .NET 8 wird native AOT-Kompilierung von den folgenden ASP.NET Core-App-Typen unterstützt:

Web-API-Vorlage (native AOT-Kompilierung)

Die ASP.NET Core-Web-API-Vorlage (native AOT-Kompilierung) (Kurzname webapiaot) erstellt ein Projekt mit aktivierter AOT-Kompilierung. Die Vorlage unterscheidet sich wie folgt von der Web-API-Projektvorlage:

  • Verwendet nur minimale APIs, da MVC noch nicht mit nativer AOT-Kompilierung kompatibel ist.
  • Verwendet die CreateSlimBuilder()-API, um sicherzustellen, dass nur die wesentlichen Features standardmäßig aktiviert sind, wodurch die bereitgestellte Größe der App minimiert wird.
  • Ist so konfiguriert, dass nur auf HTTP gelauscht wird, weil HTTPS-Datenverkehr in cloudnativen Bereitstellungen häufig von einem Eingangsdienst verarbeitet wird.
  • Enthält kein Startprofil für die Ausführung unter IIS oder IIS Express.
  • Erstellt eine .http-Datei, die mit HTTP-Beispielanforderungen konfiguriert ist, die an die Endpunkte der App gesendet werden können.
  • Enthält eine Beispiel-Todo-API anstelle des Beispiels für die Wettervorhersage.
  • Fügt PublishAot zur Projektdatei hinzu, wie weiter oben in diesem Artikel gezeigt.
  • Aktiviert die JSGeneratoren der ON-Serialisierungsquelle. Der Quellgenerator wird verwendet, um Serialisierungscode zur Buildzeit zu generieren. Dies ist für native AOT-Kompilierung erforderlich.

Änderungen zur Unterstützung von Quellgenerierung

Das folgende Beispiel zeigt den Code, der der Datei Program.cs hinzugefügt wurde, um JSGenerierung der ON-Serialisierungsquelle zu unterstützen:

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
+{
+
+}

Ohne diesen zusätzlichen Code verwendet System.Text.Json Reflexion zum Serialisieren und Deserialisieren von JSON. Reflexion wird in nativer AOT-Kompilierung nicht unterstützt.

Weitere Informationen finden Sie unter:

Änderungen an launchSettings.json

Die launchSettings.json-Datei, die von der Web-API-Vorlage (native AOT-Kompilierung) erstellt wurde, hat den Abschnitt iisSettings und das IIS Express-Profil entfernt:

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

Die CreateSlimBuilder -Methode

Die Vorlage verwendet die CreateSlimBuilder()-Methode anstelle der CreateBuilder()-Methode.

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
{

}

Die CreateSlimBuilder-Methode initialisiert WebApplicationBuilder mit den ASP.NET Core-Mindestfunktionen, die zum Ausführen einer App erforderlich sind.

Wie bereits erwähnt, bietet die CreateSlimBuilder-Methode keine Unterstützung für HTTPS oder HTTP/3. Für Apps, die hinter einem TLS-Beendigungsproxy ausgeführt werden, sind diese Protokolle in der Regel nicht erforderlich. Beispiele finden Sie unter TLS-Abschluss und End-to-End-TSL mit Application Gateway. HTTPS kann durch Aufrufen von builder.WebHost.UseKestrelHttpsConfiguration aktiviert werden. HTTP/3 kann durch Aufrufen von WebHost.UseQuic aktiviert werden.

CreateSlimBuilder vs CreateBuilder

Die CreateSlimBuilder-Methode unterstützt die folgenden Features, die von der CreateBuilder-Methode unterstützt werden, nicht:

Die CreateSlimBuilder-Methode enthält die folgenden Features, die für eine effiziente Entwicklungsumgebung erforderlich sind:

  • JSON-Dateikonfiguration für appsettings.json und appsettings.{EnvironmentName}.json.
  • Konfiguration der Benutzergeheimnisse.
  • Konsolenprotokollierung.
  • Konfiguration der Protokollierung.

Einen Generator, der die vorgenanntenFeatures überspringt, finden Sie unter Die CreateEmptyBuilder-Methode.

Die Einbeziehung von minimalen Features besitzt Vorteile für das Kürzen sowie für AOT. Weitere Informationen finden Sie unter Kürzen eigenständiger Bereitstellungen und ausführbarer Dateien.

Ausführlichere Informationen finden Sie unter Vergleich von WebApplication.CreateBuilder mit CreateSlimBuilder.

Quellcode-Generatoren

Da nicht verwendeter Code während der Veröffentlichung für native AOT gekürzt wird, kann die App zur Laufzeit keine unbegrenzte Reflexion verwenden. Quellgeneratoren werden zum Generieren von Code verwendet, um die Notwendigkeit von Reflexion zu vermeiden. In einigen Fällen erzeugen Quellgeneratoren auch dann für AOT optimierten Code, wenn kein Generator erforderlich ist.

Um den generierten Quellcode anzuzeigen, fügen Sie die EmitCompilerGeneratedFiles-Eigenschaft der Datei .csproj einer App hinzu, wie im folgenden Beispiel gezeigt:

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

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

</Project>

Führen Sie den Befehl dotnet build aus, um den generierten Code anzuzeigen. Die Ausgabe enthält ein Verzeichnis obj/Debug/net8.0/generated/, das alle generierten Dateien für das Projekt enthält.

Der Befehl dotnet publish kompiliert auch die Quelldateien und generiert Dateien, die kompiliert werden. Darüber hinaus übergibt dotnet publish die generierten Assemblys an einen nativen IL-Compiler. Der IL-Compiler erzeugt die native ausführbare Datei. Die native ausführbare Datei enthält den nativen Computercode.

Bibliotheken und native AOT-Kompilierung

Viele der beliebten Bibliotheken, die in ASP.NET Core-Projekten verwendet werden, weisen derzeit einige Kompatibilitätsprobleme auf, wenn sie in einem Projekt für native AOT verwendet werden, z. B.:

  • Verwendung der Reflektion zum Untersuchen und Ermitteln von Typen.
  • Bedingtes Laden von Bibliotheken zur Laufzeit.
  • Automatisches Generieren von Code zum Implementieren von Funktionen.

Bibliotheken, die diese dynamischen Features verwenden, müssen aktualisiert werden, um mit nativem AOT arbeiten zu können. Sie können mithilfe von Tools wie Roslyn-Quellgeneratoren aktualisiert werden.

Bibliotheksautoren, die native AOT unterstützen möchten, werden zu folgenden Aufgaben aufgefordert:

Minimale APIs und JSON-Nutzdaten

Das Minimale API-Framework ist für das Empfangen und Zurückgeben von JSON-Nutzdaten mithilfe von System.Text.Json optimiert. System.Text.Json:

Alle Typen, die als Teil des HTTP-Textkörpers übertragen oder von Anforderungsdelegaten in Minimal-API-Apps zurückgegeben werden, müssen für einen JsonSerializerContext konfiguriert werden, der über die Abhängigkeitsinjektion von ASP.NET Core registriert ist:

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
{

}

Im hervorgehobenen Code oben:

  • Der JSON-Serialisierungskontext ist im DI-Container registriert. Weitere Informationen finden Sie unter:
  • Der benutzerdefinierte JsonSerializerContext wird mit dem [JsonSerializable]-Attribut versehen, um den aus der Quelle generierten JSON-Serialisierungscode für den ToDo-Typ zu aktivieren.

Ein Parameter für den Delegaten, der nicht an den Textkörper gebunden ist und nicht serialisierbar sein muss. Beispielsweise ein Abfragezeichenfolgenparameter, der ein umfangreicher Objekttyp ist und IParsable<T> implementiert.

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.

Bekannte Probleme

In diesem GitHub-Issue können Sie Probleme mit der nativen AOT-Unterstützung in ASP.NET Core melden oder überprüfen.

Siehe auch