配置适用于 ASP.NET Core Blazor 的裁边器

注意

此版本不是本文的最新版本。 有关当前版本,请参阅 本文的 .NET 10 版本

警告

此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 NET Core 支持策略。 有关当前版本,请参阅 本文的 .NET 10 版本

本文介绍在构建 Blazor 应用时如何控制中间语言 (IL) 裁边器。

Blazor WebAssembly 执行中间语言 (IL) 裁剪以减小发布输出的大小。 裁剪操作在发布应用程序时进行。

默认裁剪器粒度

应用 Blazor 的默认修剪粒度是 partial,这意味着只有核心框架库和那些已显式启用修剪支持的库会被修剪。 不支持完整裁剪。

有关详细信息,请参阅《裁剪选项》(.NET 文档)

配置

若要配置 IL 裁剪器,请参阅 .NET 基础知识文档中的裁剪选项一文,其中包括有关以下主题的指导:

  • 通过项目文件中的 <PublishTrimmed> 属性对整个应用禁用裁剪。
  • 控制 IL 裁剪器如何放弃未充分利用的 IL。
  • 阻止 IL 裁剪器裁剪特定程序集。
  • 要裁剪的“根”程序集。
  • 通过在项目文件中将 <SuppressTrimAnalysisWarnings> 属性设置为 false 来显示关于反射的类型的警告。
  • 控制符号裁剪和调试程序支持。
  • 设置 IL 裁剪器功能以裁剪框架库功能。

剪裁器粒度partial默认值时,IL 修整程序会剪裁基类库和标记为可修整的任何其他程序集。 若要在应用程序的任何类库项目中启用剪裁功能,请在这些项目中将 MSBuild 属性设置为<IsTrimmable>true

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

与 .NET 库相关的指南,请参阅针对精简的 .NET 库的准备

未能保留已发布应用程序所使用的类型

即使将属性设置为<PublishTrimmed>false项目文件中,修整也可能对已发布的应用产生不利影响,从而导致运行时错误。 在使用反射的应用程序中,IL 裁剪器通常无法确定运行时反射所需的类型,进而会将这些类型裁剪掉,或者从方法中裁剪掉参数名称。 对于用于 JS 互操作、JSON 序列化/反序列化以及其他操作的复杂框架类型,可能出现这种情况。

IL 裁剪器也无法在运行时对应用的动态行为作出响应。 若要确保裁剪后的应用在部署后正常工作,请在开发时经常对已发布的输出进行测试。

请考虑以下示例,该示例将 JSON 反序列化执行到 Tuple<T1,T2> 集合中(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]

若要解决丢失的类型,请考虑采用以下方法之一。

自定义类型

为了避免在依赖于反射(如 JS 互操作和 JSON 序列化)的场景中 .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>

†应用的根是指应用的根或 (.NET 8 或更高版本)项目的Blazor WebAssembly根.ClientBlazor 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>

其他资源