Share via


原生 AOT 的 ASP.NET 核心支援

ASP.NET Core 8.0 推出 .NET 原生預先 (AOT) 的支援。

為何搭配 ASP.NET Core 使用原生 AOT

發佈和部署原生 AOT 應用程式可提供下列優點:

  • 磁碟使用量最小化:使用原生 AOT 發佈時,會產生單一可執行檔,只包含支援程式所需的外部相依性程序代碼。 減少的可執行檔案大小可能會導致:
    • 較小的容器映像,例如在容器化部署案例中。
    • 從較小的映像進行部署的時間減少。
  • 減少的啟動時間:原生 AOT 應用程式可以顯示減少的啟動時間,這表示
    • 應用程式已準備好更快地服務要求。
    • 改善的部署,其中容器協調器需要管理從應用程式某個版本到另一個版本的轉換。
  • 減少的記憶體需求:原生 AOT 應用程式可以減少記憶體需求,取決於應用程式所做的工作。 減少的記憶體使用量可能會導致更大的部署密度和改善的可擴縮性。

範本應用程式是在基準實驗室中執行,以比較下列應用程式的效能:AOT 發佈的應用程式、修剪的執行階段應用程式,以及未修剪的執行階段應用程式。 下圖顯示基準的結果:

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.

上圖顯示 Native AOT 的應用程式大小、記憶體使用量和啟動時間較低。

ASP.NET Core 和原生 AOT 相容性

ASP.NET Core 中的所有功能目前都與原生 AOT 相容。 下表摘要說明與原生 AOT ASP.NET Core 功能相容性:

功能 完全支援 部分支援 不支援
gRPC 完全支援
最小 API 部分支援
MVC 不支援
Blazor Server 不支援
SignalR 不支援
JWT 驗證 完全支援
其他驗證 不支援
CORS 完全支援
HealthChecks 完全支援
HttpLogging 完全支援
當地語系化 完全支援
OutputCaching 完全支援
RateLimiting 完全支援
RequestDecompression 完全支援
ResponseCaching 完全支援
ResponseCompression 完全支援
Rewrite 完全支援
工作階段 不支援
Spa 不支援
StaticFiles 完全支援
WebSocket 完全支援

如需限制的詳細資訊,請參閱:

移至原生 AOT 部署模型時,請務必徹底測試應用程式。 應該測試 AOT 部署的應用程式,以驗證功能是否尚未從未修剪的應用程式和 JIT 編譯的應用程式變更。 建置應用程式時,請檢閱並更正 AOT 警告。 在發佈期間發出 AOT 警告 的應用程式可能無法正常運作。 如果在發佈時間沒有發出 AOT 警告,則已發佈的 AOT 應用程式應該與未嘗試和 JIT 編譯的應用程式相同。

原生 AOT 發佈

原生 AOT 是使用 PublishAot MSBuild 屬性啟用的。 下列範例示範如何在專案檔中啟用原生 AOT:

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

此設定會在發佈期間啟用原生 AOT 編譯,並在建置和編輯期間啟用動態程式代碼使用分析。 使用原生 AOT 發行的專案會在本機執行時使用 JIT 編譯。 AOT 應用程式與 JIT 編譯的應用程式有下列差異:

  • 與原生 AOT 不相容的功能會停用,並在運行時間擲回例外狀況。
  • 系統會啟用來源分析器,以醒目提示與原生 AOT 不相容的程式碼。 在發佈時,會再次分析整個應用程式 (包括 NuGet 套件) 是否相容。

原生 AOT 分析包含應用程式的所有程式碼,以及應用程式依賴的程式庫。 檢閱原生 AOT 警告並採取更正步驟。 最好經常發佈應用程式,以在開發生命週期早期發現問題。

在 .NET 8 中,下列 ASP.NET Core 應用程式類型支援原生 AOT:

Web API (原生 AOT) 範本

ASP.NET Core Web API (原生 AOT) 範本 (簡短名稱webapiaot) 會建立已啟用 AOT 的專案。 此範本在下列方式中與 Web API 專案範本不同:

  • 僅使用最少的 API,因為MVC尚未與原生 AOT 相容。
  • 使用 CreateSlimBuilder() API 來確保預設只會啟用基本功能,從而將應用程式的部署大小降至最低。
  • 設定為只接聽 HTTP,因為 HTTPS 流量通常是由雲端原生部署中的輸入服務處理。
  • 不包含在 IIS 或 IIS Express 下執行的啟動設定檔。
  • 建立一個使用範例 HTTP 要求所設定的 .http 檔案,這些要求可以傳送至應用程式的端點。
  • 包含範例 Todo API,而不是天氣預報範例。
  • PublishAot 新增至專案檔,如本文稍早所示。
  • 啟用 JSON 序列化程式來源產生器。 來源產生器是用來在建置階段產生串行化程序代碼,這是原生 AOT 編譯的必要專案。

支援來源產生的變更

下列範例顯示新增至 Program.cs 檔案的程式碼,以支援 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
+{
+
+}

若沒有這個新增的程式碼,System.Text.Json 會使用反映來序列化和還原序列化 JSON。 原生 AOT 不支援 反思。

如需詳細資訊,請參閱

launchSettings.json 的變更

launchSettings.json Web API (原生 AOT) 範本所建立的檔案已iisSettings移除 區段和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"
-      }
-    }
  }
}

CreateSlimBuilder 方法

此範本會使用 CreateSlimBuilder() 方法,而不是 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
{

}

CreateSlimBuilder 方法會使用執行應用程式所需的最少 ASP.NET Core 功能來初始化 WebApplicationBuilder

如先前所述,CreateSlimBuilder 方法不包含 HTTPS 或 HTTP/3 的支援。 在 TLS 終止 Proxy 後面執行的應用程式通常不需要這些通訊協定。 如需範例,請參閱 TLS 終止和端對端 TLS 搭配應用程式閘道。 HTTPS 可以藉由呼叫 builder.WebHost.UseKestrelHttpsConfiguration 啟用,而 HTTP/3 可以藉由呼叫 builder.WebHost.UseQuic 啟用。

CreateSlimBuilderCreateBuilder

CreateSlimBuilder方法不支援 方法支援的CreateBuilder下列功能:

方法 CreateSlimBuilder 包含下列有效開發體驗所需的功能:

  • appsettings.jsonappsettings.{EnvironmentName}.json 的 JSON 檔案組態。
  • 使用者祕密組態。
  • 主控台記錄。
  • 記錄設定。

如需省略上述功能的產生器,請參閱 方法CreateEmptyBuilder

包含最少功能對於修剪以及 AOT 都有好處。 如需詳細資訊,請參閱修剪獨立式部署及可執行檔

如需詳細資訊,請參閱比較WebApplication.CreateBuilderCreateSlimBuilder

來源產生器

因為未使用的程式代碼會在發佈原生 AOT 期間修剪,因此應用程式無法在運行時間使用未繫結的反映。 來源產生器是用來產生避免需要反映的程式碼。 在某些情況下,即使不需要產生器,來源產生器仍會產生針對 AOT 最佳化的程式碼。

若要檢視產生的原始程式碼,請將 EmitCompilerGeneratedFiles 屬性新增至應用程式的 .csproj 檔案,如下列範例所示:

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

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

</Project>

執行 dotnet build 命令以查看產生的程式碼。 輸出包括 obj/Debug/net8.0/generated/ 目錄,其中包含針對專案產生的所有檔案。

dotnet publish 命令也會編譯來源檔案,並產生已編譯的檔案。 此外,dotnet publish 也會將產生的組件傳遞至原生 IL 編譯器。 IL 編譯器會產生原生可執行檔。 原生可執行檔包含原生機器碼。

連結庫和原生 AOT

ASP.NET Core 專案中使用的許多熱門連結庫,目前在以原生 AOT 為目標的專案中使用時,有一些相容性問題,例如:

  • 使用反映來檢查及探索類型。
  • 有條件地在執行階段載入程式庫。
  • 即時產生程式碼以實作功能。

您必須更新使用這些動態功能的連結庫,才能使用原生 AOT。 您可以使用 Roslyn 來源產生器之類的工具來加以更新。

鼓勵希望支援原生 AOT 的連結庫作者:

基本 API 和 JSON 承載

基本 API 架構會進行最佳化,以便充分使用 System.Text.Json 接收和傳回 JSON 承載,。 System.Text.Json

在基本 API 應用程式中作為 HTTP 內容一部分傳輸或從要求委派中傳回的所有類型,都必須在透過 ASP.NET Core 相依性插入註冊的 JsonSerializerContext 上進行設定:

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
{

}

在上述醒目提示的程式碼中:

委派上「未」繫結至主體且不需要可序列化的參數。 例如,屬於豐富物件類型並實作 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.

已知問題

請參閱 此 GitHub 問題 ,以報告或檢閱 ASP.NET Core 中原生 AOT 支持的問題。

另請參閱