返回首页

.NET 中的 Native AOT:在 CoreBus 中的实现经验

本文描述了在跨平台 .NET 应用程序 CoreBus 中实现 Native AOT 的实践经验。考虑了关键问题:Avalonia 中的编译绑定、无反射序列化、跨平台构建细节、trimming 和杀毒软件误报。

CoreBus 和 Native AOT:真实难点与解决方案
Advertisement 728x90

# CoreBus 与 Native AOT:亲身实践跨平台终端的编译体验

使用 Native AOT 编译 .NET 应用程序能带来更快的启动速度和更小的分发体积,但在实际应用中,却存在诸多技术限制。本文基于真实案例,深入探讨将 Native AOT 集成到 CoreBus 中的过程——CoreBus 是一个跨平台终端,用于操作 COM 端口和 Modbus 协议。

为什么选择 Native AOT?

切换的主要驱动力是低端 PC 上缓慢的冷启动和大安装包尺寸。从 WPF 迁移到 Avalonia UI 后,应用体积缩小了约 60 MB,但要达到 10 MB 目标仍遥遥无期。Native AOT 显得是水到渠成的下一步选择,尤其适合资源受限的工业设备和嵌入式系统。

然而,从构建阶段开始,就明显需要彻底重构绑定架构、序列化和发布策略,以支持 Native AOT。

Google AdInline article slot

问题 1:Avalonia 中的编译绑定

Avalonia 默认通过反射实现动态绑定,这与 Native AOT 不兼容。解决方案是启用预编译绑定:

<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>

这要求在每个 XAML 文件的根元素(WindowUserControl)以及 DataTemplate 中显式指定数据类型,使用 x:DataType 属性。遗漏该属性会导致编译错误(Dynamic code generation is not supported on this platform)或启动后立即崩溃。

在 CoreBus 项目中,这意味着要更新所有 XAML 标记,虽然耗时颇多,但彻底消除了运行时异常。

Google AdInline article slot

问题 2:无反射序列化

CoreBus 的设置和预设通过 System.Text.Json 存储在 JSON 文件中。标准序列化方法标注了 RequiresUnreferencedCodeRequiresDynamicCode 属性,在 Native AOT 构建时会触发 IL2026 和 IL3050 警告。

解决方案是使用源生成 JSON 序列化器,通过 JsonSerializerContext 实现。以下是一个正确的示例:

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
    TypeInfoResolver = SerializerContext.Default
};

using var stream = new FileStream(correctFilePath, FileMode.Open);
var jsonTypeInfo = options.TypeInfoResolver.GetTypeInfo(typeof(T), options);

if (jsonTypeInfo == null)
{
    throw new Exception($"Not succeeded nayti type {typeof(T)} in obyavlenii konteksta serializatsii.");
}

JsonSerializer.Serialize(stream, data, jsonTypeInfo);

反序列化时采用类似方法:

Google AdInline article slot
var data = (T?)JsonSerializer.Deserialize(stream, typeof(T), SerializerContext.Default);

这样完全避免了反射,确保与裁剪和 AOT 兼容。

问题 3:跨平台构建

Native AOT 需要针对目标操作系统和架构进行原生编译。Linux 内核版本和 glibc 对兼容性至关重要:

  • 在 Ubuntu 24.10(内核 6.11)上构建,无法在 Astra Linux CE(内核 5.15)上运行。
  • 在 Ubuntu 18.04(glibc 2.27)上构建,在 Astra Linux CE(glibc 2.24)上失败,因为 C 库缺少向后兼容性。

最终策略:

  • Windows:在 Windows 11 上构建,在 Windows 7/10 上测试——兼容性良好。
  • Linux:直接在配备内核 5.4 和 glibc 2.24 的 Astra Linux CE 上构建。

这最大化了可移植性,但使 CI/CD 流程变得复杂。

问题 4:裁剪与依赖程序集

裁剪(移除未用代码)在主可执行项目中节省最大,辅助库总计节省不到 300 KB。

然而,激进裁剪可能移除关键 Avalonia 资源,尤其是样式。建议显式排除主题:

<ItemGroup>
    <TrimmerRootAssembly Include="Avalonia.Themes.Fluent" />
</ItemGroup>

虽然在 Avalonia 11.3.x 中可能并非必需,但保留此设置作为保险措施。

问题 5:杀毒软件的误报

使用 Native AOT + 裁剪构建的应用程序常被标记为恶意软件。Windows Defender 将安装程序标记为 Trojan:Win32/Bearfoos.B!ml,便携版标记为 Trojan:Script/Wacatac.B!ml

这是已知问题,与二进制结构变化和缺少数字签名有关。解决方案是通过 Microsoft SmartScreen 验证并添加数字签名。

主要经验教训

  • Native AOT 要求彻底摒弃反射和动态代码生成。
  • 编译必须在目标平台上进行,考虑内核和系统库版本。
  • JSON 处理必须使用源生成序列化。
  • 裁剪可能破坏 UI 资源——手动排除关键程序集。
  • 杀毒工具常对无签名的 AOT 二进制文件误报。

— Editorial Team

Advertisement 728x90

继续阅读