obsługa platformy ASP.NET Core dla natywnej usługi AOT

ASP.NET Core 8.0 wprowadza obsługę natywnej platformy .NET przed czasem (AOT).

Dlaczego warto używać natywnej AOT z platformą ASP.NET Core

Publikowanie i wdrażanie natywnej aplikacji AOT zapewnia następujące korzyści:

  • Zminimalizowane zużycie dysku: podczas publikowania przy użyciu natywnej funkcji AOT jest tworzony pojedynczy plik wykonywalny zawierający tylko kod z zależności zewnętrznych, które są potrzebne do obsługi programu. Zmniejszony rozmiar pliku wykonywalnego może prowadzić do:
    • Mniejsze obrazy kontenerów, na przykład w scenariuszach wdrażania konteneryzowanego.
    • Skrócony czas wdrażania z mniejszych obrazów.
  • Skrócony czas uruchamiania: natywne aplikacje AOT mogą pokazywać skrócone czasy uruchamiania, co oznacza
    • Aplikacja jest gotowa do szybszego obsługi żądań.
    • Ulepszone wdrożenie, w którym koordynatorzy kontenerów muszą zarządzać przejściem z jednej wersji aplikacji do innej.
  • Mniejsze zapotrzebowanie na pamięć: natywne aplikacje AOT mogą mieć mniejsze zapotrzebowanie na pamięć w zależności od pracy wykonywanej przez aplikację. Zmniejszenie zużycia pamięci może prowadzić do większej gęstości wdrożenia i zwiększenia skalowalności.

Aplikacja szablonu została uruchomiona w naszym laboratorium porównawczym, aby porównać wydajność opublikowanej aplikacji AOT, przyciętej aplikacji środowiska uruchomieniowego i nietrimmed aplikacji środowiska uruchomieniowego. Na poniższym wykresie przedstawiono wyniki testów porównawczych:

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.

Na poprzednim wykresie pokazano, że natywna usługa AOT ma mniejszy rozmiar aplikacji, użycie pamięci i czas uruchamiania.

zgodność ASP.NET Core i natywna funkcja AOT

Nie wszystkie funkcje w systemie ASP.NET Core są obecnie zgodne z natywną funkcją AOT. Poniższa tabela zawiera podsumowanie zgodności funkcji ASP.NET Core z natywną funkcją AOT:

Funkcja W pełni obsługiwane Częściowo obsługiwane Nieobsługiwany
gRPC W pełni obsługiwane
Minimalne interfejsy API Częściowo obsługiwane
MVC Nieobsługiwane
Blazor Server Nieobsługiwane
SignalR Nieobsługiwane
Uwierzytelnianie JWT W pełni obsługiwane
Inne uwierzytelnianie Nieobsługiwane
CORS W pełni obsługiwane
Kontrole kondycji W pełni obsługiwane
Rejestrowanie http W pełni obsługiwane
Lokalizacja W pełni obsługiwane
Dane wyjściowe Buforowanie W pełni obsługiwane
RateLimiting W pełni obsługiwane
RequestDecompression W pełni obsługiwane
Odpowiedź Buforowanie W pełni obsługiwane
OdpowiedźKompresja W pełni obsługiwane
Przepisać W pełni obsługiwane
Sesja Nieobsługiwane
Spa Nieobsługiwane
StaticFiles W pełni obsługiwane
Protokoły WebSocket W pełni obsługiwane

Aby uzyskać więcej informacji na temat ograniczeń, zobacz:

Ważne jest, aby dokładnie przetestować aplikację podczas przechodzenia do natywnego modelu wdrażania AOT. Aplikacja wdrożona przez usługę AOT powinna zostać przetestowana w celu sprawdzenia, czy funkcjonalność nie została zmieniona z niezatrimmed i skompilowanej aplikacji JIT. Podczas kompilowania aplikacji przejrzyj i popraw ostrzeżenia dotyczące AOT. Aplikacja, która wystawia ostrzeżenia AOT podczas publikowania, może nie działać poprawnie. Jeśli w czasie publikowania nie zostaną wydane żadne ostrzeżenia dotyczące funkcji AOT, opublikowana aplikacja AOT powinna działać tak samo jak nietrimmed i skompilowana aplikacja JIT.

Publikowanie natywnej usługi AOT

Natywna funkcja AOT jest włączona z właściwością PublishAot MSBuild. W poniższym przykładzie pokazano, jak włączyć natywną funkcję AOT w pliku projektu:

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

To ustawienie umożliwia natywną kompilację AOT podczas publikowania i umożliwia dynamiczną analizę użycia kodu podczas kompilacji i edycji. Projekt korzystający z natywnego publikowania AOT używa kompilacji JIT podczas uruchamiania lokalnego. Aplikacja AOT ma następujące różnice w porównaniu z aplikacją skompilowana w trybie JIT:

  • Funkcje, które nie są zgodne z natywną funkcją AOT, są wyłączone i zgłaszają wyjątki w czasie wykonywania.
  • Analizator źródła jest włączony, aby wyróżnić kod, który nie jest zgodny z natywną funkcją AOT. W czasie publikowania cała aplikacja, w tym pakiety NuGet, jest ponownie analizowana pod kątem zgodności.

Natywna analiza AOT obejmuje cały kod aplikacji i biblioteki, od których zależy aplikacja. Przejrzyj ostrzeżenia dotyczące natywnej usługi AOT i wykonaj kroki naprawcze. Dobrym pomysłem jest częste publikowanie aplikacji w celu wykrycia problemów na wczesnym etapie cyklu projektowania.

Na platformie .NET 8 natywna funkcja AOT jest obsługiwana przez następujące typy aplikacji ASP.NET Core:

  • minimalne interfejsy API — aby uzyskać więcej informacji, zobacz sekcję szablonu interfejsu API sieci Web (natywna funkcja AOT) w dalszej części tego artykułu.
  • gRPC — aby uzyskać więcej informacji, zobacz gRPC i Native AOT.
  • Usługi robocze — aby uzyskać więcej informacji, zobacz AOT w szablonach usługi roboczej.

Szablon interfejsu API sieci Web (natywna funkcja AOT)

Szablon ASP.NET Core Web API (native AOT) (krótka nazwawebapiaot) tworzy projekt z włączoną funkcją AOT. Szablon różni się od szablonu projektu internetowego interfejsu API w następujący sposób:

  • Używa tylko minimalnych interfejsów API, ponieważ usługa MVC nie jest jeszcze zgodna z natywną funkcją AOT.
  • Używa interfejsu CreateSlimBuilder() API, aby upewnić się, że tylko podstawowe funkcje są domyślnie włączone, minimalizując rozmiar wdrożonej aplikacji.
  • Jest skonfigurowany do nasłuchiwania tylko w protokole HTTP, ponieważ ruch HTTPS jest często obsługiwany przez usługę ruchu przychodzącego we wdrożeniach natywnych dla chmury.
  • Nie zawiera profilu uruchamiania do uruchamiania w usługach IIS lub IIS Express.
  • .http Tworzy plik skonfigurowany przy użyciu przykładowych żądań HTTP, które można wysyłać do punktów końcowych aplikacji.
  • Zawiera przykładowy Todo interfejs API zamiast przykładu prognozy pogody.
  • Dodaje PublishAot do pliku projektu, jak pokazano wcześniej w tym artykule.
  • JSWłącza generatory źródeł serializatora ON. Generator źródła służy do generowania kodu serializacji w czasie kompilacji, który jest wymagany do kompilacji natywnej AOT.

Zmiany w zakresie obsługi generowania źródła

W poniższym przykładzie pokazano kod dodany do Program.cs pliku w celu obsługi JSgenerowania źródła serializacji ON:

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

Bez tego dodanego kodu System.Text.Json użyto odbicia w celu serializacji i deserializacji JSWŁ. Emocje ion nie jest obsługiwany w natywnej usłudze AOT.

Aby uzyskać więcej informacji, zobacz:

Zmiany w launchSettings.json

Plik launchSettings.json utworzony przez szablon interfejsu API sieci Web (natywny AOT) zawiera sekcję iisSettings i IIS Express profil został usunięty:

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

Metoda CreateSlimBuilder

Szablon używa CreateSlimBuilder() metody zamiast CreateBuilder() metody .

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
{

}

Metoda CreateSlimBuilder inicjuje WebApplicationBuilder element z minimalnymi funkcjami ASP.NET Core niezbędnymi do uruchomienia aplikacji.

Jak wspomniano wcześniej, CreateSlimBuilder metoda nie obejmuje obsługi protokołu HTTPS lub HTTP/3. Te protokoły zazwyczaj nie są wymagane w przypadku aplikacji uruchamianych za serwerem proxy zakończenia protokołu TLS. Zobacz na przykład kończenie żądań protokołu TLS i kończenie szyfrowania TLS za pomocą usługi Application Gateway. Protokół HTTPS można włączyć przez wywołanie konstruktora. WebHost.UseKestrelHttpsConfiguration HTTP/3 można włączyć przez wywołanie konstruktora. WebHost.UseQuic.

Klasa CreateSlimBuilder a klasa CreateBuilder

Metoda CreateSlimBuilder nie obsługuje następujących funkcji obsługiwanych przez metodę CreateBuilder :

Metoda CreateSlimBuilder zawiera następujące funkcje potrzebne do wydajnego środowiska programistycznego:

  • JSKonfiguracja pliku ON dla i appsettings.jsonappsettings.{EnvironmentName}.json.
  • Konfiguracja wpisów tajnych użytkownika.
  • Rejestrowanie konsoli.
  • Konfiguracja rejestrowania.

Aby zapoznać się z konstruktorem pomijającym poprzednie funkcje, zobacz CreateEmptyBuilder Metoda .

Włączenie minimalnych funkcji ma zalety przycinania, a także AOT. Aby uzyskać więcej informacji, zobacz Przycinanie samodzielnych wdrożeń i plików wykonywalnych.

Aby uzyskać bardziej szczegółowe informacje, zobacz Porównanie WebApplication.CreateBuilder z CreateSlimBuilder

Generatory źródeł

Ponieważ nieużywany kod jest przycinany podczas publikowania dla natywnej AOT, aplikacja nie może używać niezwiązanego odbicia w czasie wykonywania. Generatory źródeł są używane do tworzenia kodu, który pozwala uniknąć konieczności odbicia. W niektórych przypadkach generatory źródłowe generują kod zoptymalizowany pod kątem AOT nawet wtedy, gdy generator nie jest wymagany.

Aby wyświetlić wygenerowany kod źródłowy, dodaj EmitCompilerGeneratedFiles właściwość do pliku aplikacji .csproj , jak pokazano w poniższym przykładzie:

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

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

</Project>

Uruchom polecenie , dotnet build aby wyświetlić wygenerowany kod. Dane wyjściowe zawierają obj/Debug/net8.0/generated/ katalog zawierający wszystkie wygenerowane pliki dla projektu.

Polecenie dotnet publish kompiluje również pliki źródłowe i generuje skompilowane pliki. Ponadto dotnet publish przekazuje wygenerowane zestawy do natywnego kompilatora IL. Kompilator IL tworzy natywny plik wykonywalny. Natywny plik wykonywalny zawiera natywny kod maszyny.

Biblioteki i natywna usługa AOT

Wiele popularnych bibliotek używanych w projektach ASP.NET Core ma obecnie pewne problemy ze zgodnością w przypadku użycia w projekcie przeznaczonym dla natywnej funkcji AOT, takich jak:

  • Używanie odbicia do sprawdzania i odnajdywania typów.
  • Warunkowe ładowanie bibliotek w czasie wykonywania.
  • Generowanie kodu na bieżąco w celu zaimplementowania funkcji.

Biblioteki korzystające z tych funkcji dynamicznych należy zaktualizować w celu pracy z natywną usługą AOT. Można je aktualizować przy użyciu narzędzi, takich jak generatory źródeł Roslyn.

Autorzy bibliotek, którzy mają nadzieję obsługiwać natywną usługę AOT, są zachęcani do:

Minimalne interfejsy API i JSładunki WŁ.

Minimalna struktura interfejsu API jest zoptymalizowana pod kątem odbierania i zwracania JSładunków PRZY użyciu polecenia System.Text.Json. System.Text.Json:

  • Nakłada wymagania dotyczące zgodności dla JSfunkcji ON i Native AOT.
  • Wymaga użycia generatora źródłowego.System.Text.Json

Wszystkie typy przesyłane jako część treści HTTP lub zwracane z delegatów żądań w aplikacjach minimalnych interfejsów API muszą być skonfigurowane na obiekcie JsonSerializerContext , który jest zarejestrowany za pośrednictwem wstrzykiwania zależności 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
{

}

W poprzednim wyróżnionym kodzie:

Parametr delegata, który nie jest powiązany z treścią i nie musi być serializowalny. Na przykład parametr ciągu zapytania, który jest bogatym typem obiektu i implementuje IParsable<T>element .

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.

Znane problemy

Zobacz ten problem z usługą GitHub, aby zgłosić lub przejrzeć problemy z natywną obsługą usługi AOT w usłudze ASP.NET Core.

Zobacz też