Neu in .NET 8.0 [33]: Erweiterung des AOT-Compilers

Der AOT-Compiler kann auch Webservices und Hintergrunddienste übersetzen, aber mit einigen Einschränkungen.

In Pocket speichern vorlesen Druckansicht
Code kommt aus einem Tunnel

(Bild: Bild erstellt mit KI)

Lesezeit: 5 Min.
Von
  • Dr. Holger Schwichtenberg
Inhaltsverzeichnis

Mit .NET 7.0 liefert Microsoft erstmals einen Ahead-of-Timer-Compiler (AOT), der es erlaubt, .NET-Anwendungen komplett in Maschinencode ohne Just-in-Time-Kompilierung zur Laufzeit auszuliefern. Der "Native AOT" genannte Compiler konnte in .NET 7.0 jedoch nur Konsolenanwendungen übersetzen.

Der Dotnet-Doktor – Holger Schwichtenberg

Dr. Holger Schwichtenberg ist technischer Leiter des Expertennetzwerks www.IT-Visions.de, das mit 53 renommierten Experten zahlreiche mittlere und große Unternehmen durch Beratungen und Schulungen sowie bei der Softwareentwicklung unterstützt. Durch seine Auftritte auf zahlreichen nationalen und internationalen Fachkonferenzen sowie mehr als 90 Fachbücher und mehr als 1500 Fachartikel gehört Holger Schwichtenberg zu den bekanntesten Experten für .NET und Webtechniken in Deutschland.

Seit .NET 8.0 sind nun zusätzlich auch folgende Anwendungsarten beim AOT-Compiler möglich:

  • Hintergrunddienste (Worker Services)
  • gRPC-Dienste
  • WebAPIs mit Einschränkungen: Bei den WebAPIs ist lediglich das "Minimal WebAPI" genannte Modell möglich, mit JSON-Serialisierung via System.Text.Json im Source-Generator-Modus.

Weitere Einschränkungen zeigt folgende Abbildung:

Unterstützte ASP.NET Core-Features in Native AOT in .NET 8.0

(Bild: Microsoft)

Hinweis: Native AOT funktioniert weiterhin dort nicht, wo es am nötigsten wäre, um die Startzeit und den RAM-Bedarf zu verringern: Windows Forms und WPF.

Den Source Generator in System.Text.Json hat Microsoft ausgebaut, sodass er nun fast alle Konfigurationsoptionen wie der Reflection-basierte Modus kennt. Zudem funktioniert der Source-Generator jetzt zusammen mit den Init Only Properties aus C# 9.0 und den Required Properties aus C# 11.0. Den alten Reflection-Modus kann man durch eine Projekteinstellung komplett deaktivieren. Den Modus prüft die Bedingung

if (JsonSerializer.IsReflectionEnabledByDefault) { … }

Neu in .NET 8.0 ist auch, dass es bei einigen Projektvorlagen nun direkt möglich ist, den AOT-Compiler mit der Kommandozeilenoption —aot oder mit einem Häkchen in Visual Studio zu aktivieren:

  • Konsolenanwendung: dotnet new console –aot
  • Worker Service: dotnet new worker –aot
  • gRPC: dotnet new grpc –-aot

Für dotnet new existiert der Parameter --aot.

(Bild: Screenschot (Holger Schwichtenberg))

In Visual Studio bietet die Projektvorlage für gRPC-Dienste eine native AOT-Option.

(Bild: Screenshot (Holger Schwichtenberg))

Bei der Projektvorlage für ASP.NET Core WebAPIs (Kurzname webapi) gibt es keine Option —aot und kein Häkchen in Visual Studio. Hier hat sich Microsoft entschlossen, eine eigene Projektvorlage zu bauen "ASP.NET Core WebAPI (native AOT)" mit Kurznamen webapiaot. Die verwendet auch nicht das bisher in der WebAPI-Projektvorlage übliche Beispiel mit Wetterdaten, sondern eine Aufgabenliste.

Unter den WebAPI-Projektvorlagen in Visual Studio findet sich eine für native AOT.

(Bild: Screenshot (Holger Schwichtenberg))

Unterschiede zum normalen Minimal WebAPI-Template sind:

  • WebApplication.CreateSlimBuilder() statt CreateBuilder()
  • JSON-Serialisierung via Source-Generator

Folgender Code liefert eine Aufgabenliste statt einer Wettervorhersage:

using System.Text.Json.Serialization;
 
namespace MinimalWebAPI_AOT;
public class Program
{
 public static void Main(string[] args)
 {
  var builder = WebApplication.CreateSlimBuilder(args);
 
  builder.Services.ConfigureHttpJsonOptions(options =>
  {
   options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
  });
 
  var app = builder.Build();
 
  var sampleTodos = new Todo[] {
            new(1, "Walk the dog"),
            new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)),
            new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))),
            new(4, "Clean the bathroom"),
            new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2)))
        };
 
  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();
 }
}
 
public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplete = false);
 
[JsonSerializable(typeof(Todo[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
 
}

Hinweis: Alternativ kann man den Native AOT Compiler auch wie bisher nachträglich per Tag in der Projektdatei aktivieren:

<PublishAot>true</PublishAot>

und konfigurieren:

<IlcOptimizationPreference>Speed</IlcOptimizationPreference>

oder:

<IlcOptimizationPreference>Size</IlcOptimizationPreference>

Auch bei dotnet publish lässt sich Native AOT noch aktivieren:

dotnet publish -r win-x64 -c Release -p:PublishAOT=true

Wer den AOT-Compiler für ein ASP.NET-Core-Projekt aktiviert, erhält seit .NET 8.0 Warnungen beim Aufruf von Methoden, die nicht kompatibel mit dem AOT-Compiler sind:

Die Warnung zeigt an, dass der Aufruf AddControllers() zum Aktivieren des Model-View-Controller-Frameworks nicht beim Ahead-of-Timer-Compiler möglich ist.

(Bild: Screenshot (Holger Schwichtenberg))

Microsoft ermöglicht es seit .NET 8.0, .NET-Anwendungen für iOS, Mac Catalyst und tvOS mithilfe des neuen .NET-Native-AOT-Compilers zu kompilieren. Diese Möglichkeit gibt es sowohl für Apps, die auf diese Plattformen beschränkt sind (.NET for iOS), als auch für das .NET Multi-Platform App UI (.NET MAUI). Dadurch laufen die Anwendungen nicht mehr auf Mono, und die App-Pakete für ".NET for iOS" werden spürbar kompakter. Hingegen verzeichnen die App-Pakete für .NET MAUI eine Zunahme in ihrer Größe.

In einem Blogeintrag bestätigt Microsoft, dass die Firma das Problem erkannt hat und aktiv an einer Lösung arbeitet, die zu einem Größenvorteil von etwa 30 Prozent führen soll.

Die Tabelle zeigt die Verkleinerung der App-Pakete durch Native AOT.

(Bild: Microsoft)

Datenbankzugriffe sind beim AOT-Compiler weiterhin nicht mit dem Objekt-Relationalen Mapper Entity Framework Core möglich, da dieser immer noch Laufzeitkompilierung verwendet. Gleiches gilt für den zweitwichtigsten OR-Mapper der .NET-Welt, den Micro-ORM Dapper. In AOT-kompilierten Anwendungen können Entwicklerinnen und Entwickler derzeit nur DataReader, DataSet und Command-Objekte aus ADO.NET oder das GitHub-Projekt NanORM verwenden.

Online-Konferenz zu .NET 9.0 am 19. November

Auf der Online-Konferenz betterCode() .NET 9.0 am 19. November 2024 von iX und dpunkt.verlag präsentieren .NET-Experten von www.IT-Visions.de (u.a. der Autor dieses Blogbeitrags) den fertigen Stand von .NET 9.0 anhand von Praxisbeispielen. Dazu zählen die Neuerungen in .NET 9.0 SDK, C# 13.0, ASP.NET Core 9.0, Blazor 9.0, Windows Forms 9.0, WPF 9.0, WinUI, .NET MAUI 9.0 und die Integration von Künstlicher Intelligenz in .NET-Anwendungen. Das Programm bietet sechs Vorträge, eine Diskussion und sechs Workshops.

Bis zum 22. Oktober sind Tickets zum Frühbucherpreis erhältlich.

Folgendes ist mit Native AOT auch in .NET 8.0 nicht möglich, selbst wenn man eine der oben aufgeführten Anwendungsarten erstellt:

  • Laufzeitcodegenerierung (Reflection Emit)
  • Dynamisches Nachladen von Assemblies (Add-Ins/Plug-Ins)
  • Component Object Model (COM)
  • Windows Runtime-APIs (WinRT)
  • Windows Management Instrumentation (WMI)
  • Zugriff auf Active Directory Services
  • C++/CLI
  • AOT mit WebAPIs in den Internet Information Services (IIS)
  • Entity Framework Core
  • Dapper
  • JSON-Serialisierung mit JSON.NET (Newtonsoft JSON)
  • AutoMapper und viele andere Drittanbieterbibliotheken

Möglich sind dagegen unter anderem

  • Reguläre Ausdrücke
  • Dateisystemzugriffe
  • JSON-Serialisierung mit System.Text.Json
  • NET
  • NanORM
  • Dependency Injection mit Microsoft Dependency Injection-Container (Microsoft.Extensions.DependencyInjection) und AutoFac

Für .NET 8.0 hat Microsoft Zahlen herausgegeben, welche Auswirkungen der Native-AOT-Compiler auf WebAPIs hat. Man sieht in der Grafik Folgendes:

  • Die Größe des Kompilats, der RAM-Bedarf – insbesondere auf Linux – und die Startdauer werden wesentlich geringer.
  • Die Ausführungsgeschwindigkeit sinkt aber leider auch etwas, denn der Native-AOT-kompilierte Code schafft weniger Requests per Second (RPS).

Die Grafik zeigt die Auswirkung des Native-AOT-Compilers auf die Performance.

(Bild: Microsoft)

(rme)