目录

DotNetBrowser 中的裁剪和 Native AOT 支持

本文介绍了相关变更、可用能力,以及在使用这些部署模式时如何正确配置应用程序。

裁剪 

裁剪是 .NET 在发布阶段提供的一项功能,用于移除链接器判断为永远不会调用的 IL 代码。这样可以减小发布产物的体积,因为未引用的类型、方法和资源都会从输出中移除。

风险在于,某些仅在运行时通过反射或动态加载发现的代码可能会被裁掉,从而在运行时导致 MissingMethodException 或类似错误。

为了能够安全地供启用裁剪的应用程序使用,库必须声明 IsTrimmable=true,并为所有相关代码路径添加注解,让链接器知道哪些成员需要保留。

Native AOT 

Native AOT 会在发布时将整个 .NET 应用程序编译为独立的原生二进制文件。 运行时没有 JIT 编译器,不支持基于反射的代码生成,也不支持 Assembly.Load。 这可以显著降低启动时间和内存开销,但也是 .NET 支持的最严格的部署模式。

DotNetBrowser 中的变更 

兼容的软件包 

目前,所有 DotNetBrowser 核心软件包在 .NET 8 目标框架下都声明了 IsTrimmable=trueIsAotCompatible=true

说明
DotNetBrowser公共 API 接口
DotNetBrowser.Core核心实现
DotNetBrowser.Logging日志基础设施
DotNetBrowser.AvaloniaUiAvalonia UI 集成

注意: DotNetBrowser 仅在控制台应用程序和 Avalonia UI 11.x 版本(从 11.2.0 开始)中支持裁剪和 AOT。

Native AOT 部署要求 

由于 Native AOT 模式下无法加载程序集,因此不支持内置 Chromium 二进制文件的自动提取。在应用程序启动之前,必须先将 Chromium 二进制文件部署到已知目录中。

第 1 步:预先部署 Chromium 二进制文件 

将 Chromium 二进制文件复制到目标机器上的某个目录。该目录中的结构依赖于平台和体系结构:

<chromium-dir>/
  Windows 二进制文件  → WindowsX86/, WindowsX64/, WindowsArm64/
  Linux 二进制文件    → LinuxX64/, LinuxArm64/
  macOS 二进制文件    → MacX64/, MacArm64/

第 2 步:告诉 DotNetBrowser 二进制文件的位置 

方式 A:环境变量(无需修改代码):

# Linux / macOS
export DOTNETBROWSER_CHROMIUM_DIR=/opt/myapp/chromium

# Windows
set DOTNETBROWSER_CHROMIUM_DIR=C:\myapp\chromium

方式 B:EngineOptions.ChromiumDirectory(在代码中配置):

C#
VB
var engine = EngineFactory.Create(new EngineOptions.Builder
{
    ChromiumDirectory = "/opt/myapp/chromium"
}.Build());
Dim engine = EngineFactory.Create(
    New EngineOptions.Builder() With {
        .ChromiumDirectory = "/opt/myapp/chromium"
    }.Build()
)

如果上述两种方式都没有配置,且二进制文件不存在,DotNetBrowser 会抛出 ChromiumBinariesMissingException

使用 Native AOT 发布 

下面是在 Linux 上使用 DotNetBrowser 和 Avalonia UI 的 Native AOT 应用程序的最小 .csproj 配置:

<PropertyGroup>
  <OutputType>WinExe</OutputType>
  <TargetFramework>net8.0</TargetFramework>
  <PublishAot>true</PublishAot>
  <Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
  <PackageReference Include="DotNetBrowser.AvaloniaUi" Version="..." />
</ItemGroup>

发布命令:

dotnet publish -c Release -r linux-x64

发布输出中不包含 Chromium 二进制文件。你需要单独部署这些文件,并按照上文所述配置其路径。

仅使用裁剪发布 

如果你希望在不使用 Native AOT 的情况下减小输出体积,可以只启用裁剪:

<PropertyGroup>
  <OutputType>WinExe</OutputType>
  <TargetFramework>net8.0</TargetFramework>
  <PublishTrimmed>true</PublishTrimmed>
  <Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
  <PackageReference Include="DotNetBrowser.AvaloniaUi" Version="..." />
</ItemGroup>

在这种模式下,Chromium 二进制文件可以像普通应用程序一样,在首次启动时从 NuGet 包中自动提取。 唯一额外需要完成的部署步骤,是确保包含 DotNetBrowser.Chromium.X.dll 程序集,因为在发布期间由于没有直接引用,它不会被自动复制。

支持的 UI 框架 

在此版本中,只有 Avalonia UI 集成支持裁剪和 Native AOT。

WPF、WinForms 和 WinUI3 不兼容裁剪和 Native AOT。

已知限制 

在 AOT 模式下必须预先部署 Chromium 二进制文件。 Native AOT 应用程序不支持从 NuGet 嵌入资源中自动提取这些文件。

基于反射的 JS 便捷重载。 某些 IJsObject 互操作帮助程序在内部使用了反射。 这些代码路径已经添加了注解,因此调用时是安全的;但如果你大量使用 dynamic 类型的 JS 返回结果,建议在具体的 AOT 场景中验证其行为。

从 JavaScript 调用 .NET。 需要添加 [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(MyObject))] 特性,以确保注入的对象在裁剪过程中被保留。 如果没有添加该特性,该对象可能会被裁剪器移除,从而在运行时不可用。 示例代码如下:

C#
VB
public class MyObject {
    [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(MyObject))]
    public string SayHelloTo(string firstName) {
        return "Hello " + firstName + "!";
    }
}
Public Class MyObject
    <DynamicDependency(DynamicallyAccessedMemberTypes.All, GetType(MyObject))>
    Public Function SayHelloTo(ByVal firstName As String) As String
        Return "Hello " & firstName & "!"
    End Function
End Class
C#
VB
IJsObject window = frame.ExecuteJavaScript<IJsObject>("window").Result;
window.Properties["MyObject"] = new MyObject();
Dim window As IJsObject = frame.ExecuteJavaScript(Of IJsObject)("window").Result
window.Properties("MyObject") = New MyObject()

完成后,你就可以在 JavaScript 代码中引用该对象并调用其方法:

console.log(window.MyObject.SayHelloTo("John"));