AOT 支持
自.NET8,.NET团队在逐步做NativeAOT支持。
本框架支持这种发布方式:核心包、驱动包与部分扩展包都做了NativeAOT适配,并标注了 IsAotCompatible。
但NativeAOT并不是免费的午餐。你要做提前编译,就意味着要限制动态特性。有一些能力要么不能再用、要么需要额外登记。幸运的是,StdUnit.Tags类库家族对NativeAOT的支持良好,仅有两个场景需要特殊注意。
各包就绪情况
| 分组 | 包 | 状态 | 备注 |
|---|---|---|---|
| 核心 | StdUnit.Tags.Core | ✅ | |
| 核心 | StdUnit.Tags | ✅ | <Logicet/> 动态插件除外,见下文「<Logicet/> 动态插件在 AOT 下不可用」 |
| 扩展 | StdUnit.Tags.R3Extensions | ✅ | |
| 扩展 | StdUnit.Tags.McpServer | ✅ | |
| 扩展 | StdUnit.Tags.RxExtensions | ❌ | 底层 System.Reactive 目前对 AOT 支持不好 |
| 扩展 | StdUnit.Tags.BlazorLib.Core | ❌ | Blazor Server 模式不支持 AOT |
| 驱动 | StdUnit.Tags.S7 | ✅ | |
| 驱动 | StdUnit.Tags.ModbusTcp | ✅ | |
| 驱动 | StdUnit.Tags.Hjzk | ✅ | |
| 驱动 | StdUnit.Tags.ZLan | ✅ | |
| 驱动 | StdUnit.Tags.OpcUaClient | ✅ | |
| 驱动 | StdUnit.Tags.ComScanner | ✅ | |
| 驱动 | StdUnit.Tags.SimpleFiles | ✅ | JSON 测点需登记元数据,见下文「SimpleFiles 的 JSON 测点要自行登记元数据」 |
- "✅":该包自己的代码在裁剪 / AOT 分析器下零告警。第三方依赖的 AOT 告警要到
dotnet publish时才出现(见文末「备注」)。 - "❌": 由于底层限制,无法支持;或者由于时间不足,尚不支持。
<Logicet/> 动态插件在 AOT 下不可用
这是 .NET NativeAOT 运行时能力问题。NativeAOT 的官方限制里第一条就是 No dynamic loading:运行时的 AssemblyLoadContext 在 AOT 下直接抛 PlatformNotSupportedException。所以"插件 DLL 没被裁剪"并不能救它——宿主根本读不进这个文件。
所以,在 XML 里配了 <Logicet/> 的 AOT 宿主会在加载期抛 TagsProjectNotSupportedException,异常信息类似于:
TagsProjectNotSupportedException: 当前宿主运行时不支持…无法按路径挂载 <Logicet> 指定的 Logicet 插件:plugins/Demo.dll
这里我们有意在加载期抛出异常(快速失败),并推荐两种改法:
- 宿主内注册(AOT 下推荐):
project.TryAddLogicet<MyLogicet>(sp),逻辑组件跟着宿主一起编译。 - 换宿主形态:改用非 AOT(CoreCLR/JIT)发布,
<Logicet/>恢复完整能力(隔离 + 卸载)。
注意,普通 JIT 宿主不受上述影响;net472 上则是另一种降级语义(无隔离、无卸载,见 README 的「netfx 的插件化限制」)。
SimpleFiles 的 JSON 测点要自行登记元数据
JSON 测点的值类型是你自己写的 POCO,框架无法预知它的类型元数据。而 AOT / 裁剪宿主下 System.Text.Json 默认关闭反射序列化(JsonSerializer.IsReflectionEnabledByDefault 为 false),所以,和上面的手动注册ILogicet类似,这里的元数据只能由你在代码里事先注册:
[JsonSerializable(typeof(MyJson))]
internal partial class MyJsonContext : JsonSerializerContext { }
builder.AddSimpleFilesChannel()
.AddJsonSerializerContext(MyJsonContext.Default) // ← 只加这一行
.AddSimpleFilesDirectTagBuilder(
configure: b => b.WithJsonTagFactory<MyJson>(),
predicate: b => b.TagDescriptor.TagKind == "Json");
测点的注册方式不变(WithJsonTagFactory<T>() 不带任何类型元数据参数)。在AOT场景下,两种失败都会在构建测点时就报出来,而不是等第一次读写文件:
| 情况 | 异常 | 怎么改 |
|---|---|---|
| 没登记上下文 | TagsProjectNotSupportedException | 加上 AddJsonSerializerContext(...) |
登记了上下文,但里面没有该类型的 [JsonSerializable] | TagsProjectConfigurationException | 把该类型加进某个上下文 |
普通 JIT 宿主不需要登记:没有登记就退回反射序列化,行为与以前完全一致。
备注
IsAotCompatible 只说明本包代码干净。第三方依赖的 AOT 分析要到 dotnet publish 才完全现形,例如 McMaster.NETCore.Plugins会报 IL2104 / IL3053——但是注意,这个依赖包不会对我们的AOT场景有任何影响,因为在我们的代码里一旦在加载期检测到 AOT+动态插件,会当场报错。所以在dotnet publish时,看到关于McMaster.NETCore.Plugins的IL2104、IL3053这两条警告,可以放心忽略。