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

注意

此版本不是本文的最新版本。 对于当前版本,请参阅本文的 .NET 9 版本

警告

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

重要

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

对于当前版本,请参阅本文的 .NET 9 版本

本文介绍在构建 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>

其他资源