Share via


네이티브 AOT에 대한 ASP.NET Core 지원

ASP.NET Core 8.0에는 .NET 네이티브 AOT(Ahead-of-Time)에 대한 지원이 도입되었습니다.

ASP.NET Core에서 Native AOT를 사용하는 이유

네이티브 AOT 앱을 게시하고 배포하면 다음과 같은 이점이 제공됩니다.

  • 디스크 공간 최소화: Native 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의 모든 기능이 현재 Native AOT와 호환되는 것은 아닙니다. 다음 표에는 네이티브 AOT와의 ASP.NET Core 기능 호환성이 요약되어 있습니다.

기능 완전히 지원됨 부분적으로 지원됨 지원되지 않음
gRPC 완전히 지원됨
최소 API 부분적으로 지원됨
MVC 지원되지 않음
Blazor Server 지원되지 않음
SignalR 지원되지 않음
JWT 인증 완전히 지원됨
기타 인증 지원되지 않음
CORS 완전히 지원됨
HealthChecks 완전히 지원됨
HttpLogging 완전히 지원됨
지역화 완전히 지원됨
OutputCaching 완전히 지원됨
RateLimiting 완전히 지원됨
RequestDecompression 완전히 지원됨
ResponseCaching 완전히 지원됨
ResponseCompression 완전히 지원됨
재작성 완전히 지원됨
세션 지원되지 않음
온천 지원되지 않음
StaticFiles 완전히 지원됨
WebSocket 완전히 지원됨

제한 사항에 대한 자세한 내용은 다음을 참조하세요.

네이티브 AOT 배포 모델로 이동할 때 앱을 철저히 테스트하는 것이 중요합니다. AOT 배포된 앱을 테스트하여 기능이 시도되지 않고 JIT 컴파일된 앱에서 변경되지 않았는지 확인해야 합니다. 앱을 빌드할 때 AOT 경고를 검토하고 수정합니다. 게시하는 동안 AOT 경고를 실행하는 앱이 제대로 작동하지 않을 수 있습니다. 게시 시간에 AOT 경고가 실행되지 않는 경우 게시된 AOT 앱은 시도되지 않고 JIT 컴파일된 앱과 동일하게 작동해야 합니다.

네이티브 AOT 게시

네이티브 AOT는 MSBuild 속성을 사용하여 PublishAot 사용하도록 설정됩니다. 다음 예제에서는 프로젝트 파일에서 Native AOT를 사용하도록 설정하는 방법을 보여 줍니다.

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

이 설정은 게시 중에 네이티브 AOT 컴파일을 사용하도록 설정하고 빌드 및 편집 중에 동적 코드 사용 현황 분석을 사용하도록 설정합니다. 네이티브 AOT 게시를 사용하는 프로젝트는 로컬로 실행할 때 JIT 컴파일을 사용합니다. AOT 앱은 JIT 컴파일 앱과 다음과 같은 차이점이 있습니다.

  • Native AOT와 호환되지 않는 기능은 사용하지 않도록 설정되며 런타임에 예외를 throw합니다.
  • 원본 분석기는 네이티브 AOT와 호환되지 않는 코드를 강조 표시할 수 있습니다. 게시 시 NuGet 패키지를 포함한 전체 앱이 다시 호환성을 위해 분석됩니다.

네이티브 AOT 분석에는 앱의 모든 코드와 앱이 의존하는 라이브러리가 포함됩니다. 네이티브 AOT 경고를 검토하고 수정 단계를 수행합니다. 개발 수명 주기 초기에 문제를 검색하기 위해 앱을 자주 게시하는 것이 좋습니다.

.NET 8에서 Native AOT는 다음 ASP.NET Core 앱 유형에서 지원됩니다.

  • 최소 API - 자세한 내용은 이 문서의 뒷부분에 있는 웹 API(네이티브 AOT) 템플릿 섹션을 참조하세요.
  • gRPC - 자세한 내용은 gRPC 및 네이티브 AOT를 참조하세요.
  • 작업자 서비스 - 자세한 내용은 작업자 서비스 템플릿의 AOT를 참조 하세요.

Web API(네이티브 AOT) 템플릿

ASP.NET Core Web API(네이티브 AOT) 템플릿(짧은 이름webapiaot)은 AOT를 사용하도록 설정된 프로젝트를 만듭니다. 템플릿은 다음과 같은 방법으로 Web API 프로젝트 템플릿과 다릅니다.

원본 생성을 지원하기 위한 변경 내용

다음 예제에서는 ON serialization 원본 생성을 Program.cs 지원하기 JS위해 파일에 추가된 코드를 보여줍니다.

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 가 없으면 리플렉션을 사용하여 ON을 직렬화하고 역직렬화합니다 JS. 네이티브 AOT에서는 리플렉션이 지원되지 않습니다.

자세한 내용은 다음을 참조하세요.

변경 내용 launchSettings.json

launchSettings.json Web API(네이티브 AOT) 템플릿에서 만든 파일에는 섹션과 IIS Express 프로필이 iisSettings 제거됩니다.

{
  "$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 메서드

템플릿은 메서드 대신 메서드를 CreateBuilder() 사용합니다CreateSlimBuilder().

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 종료 프록시 뒤에서 실행되는 앱에 필요하지 않습니다. 예를 들어 Application Gateway를 사용한 TLS 종료 및 종단 간 TLS를 참조하세요. HTTPS는 작성기 호출 을 통해 사용하도록 설정할 수 있습니다. WebHost.UseKestrelHttpsConfiguration HTTP/3은 작성기 호출 을 통해 사용하도록 설정할 수 있습니다. WebHost.UseQuic.

CreateSlimBuilderCreateBuilder

메서드는 CreateSlimBuilder 메서드에서 지원하는 CreateBuilder 다음 기능을 지원하지 않습니다.

CreateSlimBuilder 방법은 효율적인 개발 환경에 필요한 다음 기능을 포함합니다.

  • JSON 파일 구성 및 appsettings.jsonappsettings.{EnvironmentName}.json.
  • 사용자 비밀 구성.
  • 콘솔 로깅.
  • 로깅 구성.

이전 기능을 생략하는 작성기를 보려면 The CreateEmptyBuilder 메서드를 참조하세요.

최소 기능을 포함하면 AOT뿐만 아니라 트리밍에도 이점이 있습니다. 자세한 내용은 자체 포함 배포 및 실행 파일 트리밍을 참조하세요.

자세한 내용은 비교를 WebApplication.CreateBuilder 참조하세요.CreateSlimBuilder

소스 생성기

네이티브 AOT에 대해 게시하는 동안 사용되지 않는 코드가 잘리기 때문에 앱은 런타임에 바인딩되지 않은 리플렉션을 사용할 수 없습니다. 소스 생성기는 리플렉션이 필요하지 않은 코드를 생성하는 데 사용됩니다. 경우에 따라 원본 생성기는 생성기가 필요하지 않은 경우에도 AOT에 최적화된 코드를 생성합니다.

생성된 소스 코드를 보려면 다음 예제와 같이 앱의 .csproj 파일에 속성을 추가 EmitCompilerGeneratedFiles 합니다.

<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 프로젝트에 사용되는 많은 인기 라이브러리는 현재 Native AOT를 대상으로 하는 프로젝트에서 사용할 때 다음과 같은 호환성 문제가 있습니다.

  • 리플렉션을 사용하여 형식을 검사하고 검색합니다.
  • 런타임에 라이브러리를 조건부로 로드합니다.
  • 즉시 코드를 생성하여 기능을 구현합니다.

네이티브 AOT를 사용하려면 이러한 동적 기능을 사용하는 라이브러리를 업데이트해야 합니다. Roslyn 원본 생성기와 같은 도구를 사용하여 업데이트할 수 있습니다.

네이티브 AOT를 지원하려는 라이브러리 작성자는 다음을 권장합니다.

최소 API 및 JSON 페이로드

최소 API 프레임워크는 .를 사용하여 System.Text.JsonON 페이로드를 받고 반환하는 데 JS최적화되어 있습니다. System.Text.Json:

  • ON 및 Native AOT에 JS대한 호환성 요구 사항을 적용합니다.
  • 원본 생성기를 사용해야 System.Text.Json 합니다.

HTTP 본문의 일부로 전송되거나 최소 API 앱의 요청 대리자에서 반환되는 모든 형식은 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
{

}

앞의 강조 표시된 코드에서 다음을 수행합니다.

  • JSON serializer 컨텍스트는 DI 컨테이너등록됩니다. 자세한 내용은 다음을 참조하세요.
  • 사용자 지정 JsonSerializerContext 은 소스에서 생성된 JSON serializer 코드를 형식에 사용하도록 설정하기 위해 특성으로 주석 [JsonSerializable] 을 추가합니다ToDo.

본문 에 바인딩되지 않고 직렬화할 필요가 없는 대리자의 매개 변수입니다. 예를 들어 서식 있는 개체 형식이며 구현하는 쿼리 문자열 매개 변수입니다 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.

알려진 문제

ASP.NET Core에서 네이티브 AOT 지원 문제를 보고하거나 검토하려면 이 GitHub 문제를 참조하세요.

참고 항목