推荐在Avalonia中使用Microsoft.Extensions.DependencyInjection结合AssemblyLoadContext实现插件系统:定义IPlugin等契约接口,通过隔离的AssemblyLoadContext动态加载插件DLL,插件向宿主IServiceCollection注册服务,宿主聚合INavigationProvider菜单项与IViewComponent视图并解耦通信。
在 Avalonia 中实现插件系统,推荐使用 Microsoft.Extensions.DependencyInjection(DI) 结合 MEF(Managed Extensibility Framework) 或纯 DI 方式动态加载插件。Avalonia 本身不内置插件机制,但可借助 .NET 的模块化能力(如 AssemblyLoadContext、AssemblyLoadEventArgs、接口抽象 + 运行时反射)构建松耦合、热插拔的插件架构。
所有插件必须实现约定接口,这是解耦核心。建议放在独立类库(如 MyApp.Plugins.Contracts)中供宿主和插件共同引用:
Initialize() / Shutdown())MenuItem 或 Route)ContentControl 动态渲染的 Avalonia 控件(继承自 Control)Avalonia.Controls.Button),改用抽象类型或数据模型不依赖 MEF 的轻量方案(更可控、兼容 .NET 6+):
.dll 形式存放于 Plugins/ 目录,命名规范如 MyPlugin.dll
AssemblyLoadContext 防止类型冲突:var pluginContext = new AssemblyLoadContext(isCollectible: true); var assembly = pluginContext.LoadFromAssemblyPath(pluginPath);
assembly.GetTypes(),筛选实现 IPlugin 的类型,用 Activator.CreateInstance 创建实例plugin.Initialize(services),将宿主的 IServiceCollection 传入,让插件注册自身服务(如 services.AddSingleton() )在 AppBuilder 构建阶段注入插件:
IServiceCollection(含 Avalonia 默认服务)Initialize(IServiceCollection)
BuildServiceProvider()
BuildServiceProvider**,避免容器嵌套示例片段:
var services = new ServiceCollection();
// 注册宿主服务...
RegisterHostServices(services);
// 加载插件
foreach (var pluginPath in GetPluginPaths())
{
var plugin = LoadPlugin(pluginPath);
plugin.Initialize(services); // 插件向 service
s 添加自己的类型
}
var app = BuildAvaloniaApp()
.UsePlatformDetect()
.SetupWithLifetime(lifetime);
app.StartWithClassicDesktopLifetime(args, ShutdownMode.OnMainWindowClose);
插件通过接口向宿主“声明能力”,宿主负责聚合与呈现:
INavigationProvider.GetMenuItems() → 宿主收集所有 MenuItem 并添加到主菜单IViewComponent.CreateView() → 宿主用 绑定渲染ICommand 属性,由插件提供 ViewModel 实现,宿主仅负责触发Application.Current.MainWindow),改用事件或消息总线(如 WeakEvent 或 CommunityToolkit.Mvvm.Messaging)通信不复杂但容易忽略:确保插件 DLL 不包含重复依赖(如 Avalonia.*),全部由宿主提供;发布时将插件目录设为 CopyToOutputDirectory;调试阶段可用 AssemblyResolve 事件辅助定位加载失败原因。