다음을 통해 공유


ASP.NET Core용 트리머 구성 Blazor

비고

이 기사는 최신 버전이 아닙니다. 현재 릴리스는 이 문서의 .NET 10 버전을 참조하세요.

경고

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조하세요. 현재 릴리스는 이 문서의 .NET 10 버전을 참조하세요.

이 문서에서는 앱을 빌드할 때 IL(중간 언어) 트리머를 제어하는 Blazor 방법을 설명합니다.

Blazor WebAssembly 는 IL(중간 언어) 트리밍을 수행하여 게시된 출력의 크기를 줄입니다. 트리밍은 앱을 게시할 때 발생합니다.

기본 트리머 세분성

기본적으로 Blazor 앱의 트리머 세분성은 partial이며, 이는 핵심 프레임워크 라이브러리와 트리밍 지원을 명시적으로 사용하도록 설정한 라이브러리만 잘린다는 것을 의미합니다. 전체 트리밍은 지원되지 않습니다.

자세한 내용은 트리밍 옵션(.NET 설명서)을 참조하세요.

구성 / 설정

IL 트리머를 구성하려면 다음 주제에 대한 지침을 포함하는 .NET 기본 사항 설명서의 트리밍 옵션 문서를 참조하세요.

  • 프로젝트 파일에서 <PublishTrimmed> 속성을 사용하여 전체 애플리케이션의 트리밍을 비활성화합니다.
  • IL 트리머가 적극적으로 사용하지 않는 IL을 삭제하는 방법을 제어합니다.
  • IL 트리머가 특정 어셈블리를 트리밍하지 않도록 합니다.
  • 트리밍을 위한 "루트" 조립체입니다.
  • <SuppressTrimAnalysisWarnings> 속성을 프로젝트 파일에서 false로 설정하여 반영된 유형에 대한 경고를 표시합니다.
  • 기호 트리밍 및 디버거 지원을 제어합니다.
  • 프레임워크 라이브러리 기능을 트리밍하기 위한 IL 트리머 기능을 설정합니다.

트리머 세분성이partial기본값인 경우 IL 트리머는 기본 클래스 라이브러리 및 트리밍 가능한 것으로 표시된 다른 어셈블리를 트리밍합니다. 해당 앱의 클래스 라이브러리 프로젝트에서 트리밍을 활성화하려면 해당 프로젝트에 <IsTrimmable>MSBuild 속성true을 설정하세요.

<PropertyGroup>
  <IsTrimmable>true</IsTrimmable>
</PropertyGroup>

.NET 라이브러리와 관련된 지침은 트리밍을 위한 .NET 라이브러리 준비를 참조하세요.

게시된 앱에서 사용하는 형식을 유지하지 못했습니다.

트리밍은 프로젝트 파일에서 속성을 <PublishTrimmed> 설정 하더라도 게시된 앱에 해로운 영향을 줄 수 있으며 런타임 오류가 발생할 수 있습니다. 리플렉션을 사용하는 앱에서 IL 트리머는 런타임 리플렉션에 필요한 형식을 확인할 수 없는 경우가 많으며 메서드에서 매개 변수 이름을 잘라내거나 트리밍합니다. 이는 interop, JSON serialization/deserialization 및 기타 작업에 사용되는 JS 복잡한 프레임워크 형식에서 발생할 수 있습니다.

또한 IL 트리머는 런타임에 앱의 동적 동작에 반응할 수 없습니다. 트리밍된 앱이 배포된 후 올바르게 작동하는지 확인하려면 개발하는 동안 게시된 출력을 자주 테스트합니다.

컬렉션(Tuple<T1,T2>)으로 JSON 역직렬화를 수행하는 다음 예제를 List<Tuple<string, string>> 고려해 보세요.

TrimExample.razor:

@page "/trim-example"
@using System.Diagnostics.CodeAnalysis
@using System.Text.Json

<h1>Trim Example</h1>

<ul>
    @foreach (var item in @items)
    {
        <li>@item.Item1, @item.Item2</li>
    }
</ul>

@code {
    private List<Tuple<string, string>> items = [];

    [StringSyntax(StringSyntaxAttribute.Json)]
    private const string data =
        """[{"item1":"1:T1","item2":"1:T2"},{"item1":"2:T1","item2":"2:T2"}]""";

    protected override void OnInitialized()
    {
        JsonSerializerOptions options = new() { PropertyNameCaseInsensitive = true };

        items = JsonSerializer
            .Deserialize<List<Tuple<string, string>>>(data, options)!;
    }
}

위의 구성 요소는 앱이 로컬로 실행될 때 정상적으로 실행되며 렌더링된 다음 목록을 생성합니다.

• 1:T1, 1:T2
• 2:T2, 2:T2

앱이 게시되면 Tuple<T1,T2> 프로젝트 파일에서 속성을 <PublishTrimmed> 설정 false 하더라도 앱에서 잘립니다. 구성 요소에 액세스하면 다음 예외가 발생합니다.

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: ConstructorContainsNullParameterNames, System.Tuple`2[System.String,System.String]
System.NotSupportedException: ConstructorContainsNullParameterNames, System.Tuple`2[System.String,System.String]

손실된 형식을 해결하려면 다음 방법 중 하나를 채택하는 것이 좋습니다.

사용자 지정 형식

interop 및 JSON serialization과 같이 JS 리플렉션을 사용하는 시나리오에서 .NET 트리밍 문제를 방지하려면 트리밍할 수 없는 라이브러리에 정의된 사용자 지정 형식을 사용하거나 링커 구성을 통해 형식을 유지합니다.

다음 수정은 구성 요소에서 StringTuple 사용할 형식을 만듭니다.

StringTuple.cs:

[method: SetsRequiredMembers]
public sealed class StringTuple(string item1, string item2)
{
    public required string Item1 { get; init; } = item1;
    public required string Item2 { get; init; } = item2;
}

구성 요소는 다음 형식을 사용하도록 수정됩니다.StringTuple

- private List<Tuple<string, string>> items = [];
+ private List<StringTuple> items = [];
- items = JsonSerializer.Deserialize<List<Tuple<string, string>>>(data, options)!;
+ items = JsonSerializer.Deserialize<List<StringTuple>>(data, options)!;

트리밍할 수 없는 어셈블리에 정의된 사용자 지정 형식은 앱이 게시될 때 트리밍 Blazor 되지 않으므로 구성 요소는 앱이 게시된 후 디자인된 대로 작동합니다.

권장 사항에도 불구하고 프레임워크 형식을 사용하려는 경우 다음 방법 중 하나를 사용합니다.

권장 사항에도 불구하고 프레임워크 형식을 사용하려는 경우 형식을 동적 종속성으로 유지합니다.

형식을 동적 종속성으로 유지

특성을 사용하여 형식[DynamicDependency]을 유지하는 동적 종속성을 만듭니다.

아직 없는 경우 @using에 대한 지시문을 System.Diagnostics.CodeAnalysis 추가합니다.

@using System.Diagnostics.CodeAnalysis

다음을 유지하려면 [DynamicDependency] 특성을 추가하십시오Tuple<T1,T2>.

+ [DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, 
+     typeof(Tuple<string, string>))]
private List<Tuple<string, string>> items = [];

루트 설명자 사용

루트 설명자는 형식을 유지할 수 있습니다.

형식을 사용하여 ILLink.Descriptors.xml † 앱의 루트에 파일을 추가합니다.

<linker>
  <assembly fullname="System.Private.CoreLib">
    <type fullname="System.Tuple`2" preserve="all" />
  </assembly>
</linker>

†앱의 루트는 앱의 Blazor WebAssembly 루트 또는 (.NET 8 이상) 프로젝트의 루트 .Client 를 Blazor Web App 참조합니다.

TrimmerRootDescriptor 파일을 참조하여 ILLink.Descriptors.xml 앱의 프로젝트 파일에 항목을 추가합니다.

<ItemGroup>
  <TrimmerRootDescriptor Include="$(MSBuildThisFileDirectory)ILLink.Descriptors.xml" />
</ItemGroup>

•프로젝트 파일은 앱의 Blazor WebAssembly 프로젝트 파일 또는 (.NET 8 이상) 프로젝트의 프로젝트 파일 .Client 입니다 Blazor Web App .

.NET 8의 해결 방법

.NET 8의 해결 방법으로, 트리밍 중에 매개 변수 이름을 유지하기 위해 _ExtraTrimmerArgs 앱의 프로젝트 파일에 설정된 MSBuild 속성을 추가할 --keep-metadata parametername 수 있습니다.

<PropertyGroup>
  <_ExtraTrimmerArgs>--keep-metadata parametername</_ExtraTrimmerArgs>
</PropertyGroup>

추가 리소스