如何在自定义AssemblyLoadContext中使用MEF AssemblyCatalog
问题原因
AssemblyCatalog(来自传统MEF System.ComponentModel.Composition)默认依赖默认AssemblyLoadContext来扫描程序集中的导出部件(如标记[Export]的类型)。当你将插件程序集加载到自定义可回收ALC中时,默认ALC无法访问该程序集内的类型,因此扫描不到任何部件,导致Parts属性为空。而默认ALC加载时,程序集类型对扫描逻辑完全可见,所以功能正常。
解决方案
根据你使用的MEF版本,提供两种可行方案:
方案1:使用轻量级MEF(MEF2,System.Composition)
MEF2对自定义AssemblyLoadContext的支持更友好,无需额外处理即可扫描自定义ALC中的程序集部件。
安装NuGet包:
Install-Package System.Composition Install-Package System.Composition.Hosting修改代码实现:
// 创建自定义可回收ALC var context = new AssemblyLoadContext(directoryInfo.FullName, true); // 加载插件程序集 var assembly = context.LoadFromAssemblyPath(fileInfo.FullName); // 使用MEF2的容器配置加载程序集 var containerConfig = new ContainerConfiguration() .WithAssembly(assembly); using (var container = containerConfig.CreateContainer()) { // 获取所有导出的插件实例(替换为你的插件接口) var plugins = container.GetExports<IMyPlugin>(); // 执行插件逻辑... }
方案2:自定义Catalog适配传统MEF
如果必须使用传统MEF(System.ComponentModel.Composition),可以手动实现Catalog,直接从自定义ALC加载的程序集中扫描导出类型:
using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Linq; public class AlcCompatibleAssemblyCatalog : ComposablePartCatalog { private readonly List<ComposablePartDefinition> _parts = new(); public AlcCompatibleAssemblyCatalog(Assembly assembly) { // 遍历程序集内所有类型,筛选带[Export]属性的类型 foreach (var type in assembly.GetTypes()) { if (type.GetCustomAttributes(typeof(ExportAttribute), inherit: true).Any()) { // 将符合条件的类型转换为ComposablePartDefinition _parts.Add(new TypeCatalog(type).Parts.First()); } } } public override IQueryable<ComposablePartDefinition> Parts => _parts.AsQueryable(); }
使用方式:
// 创建自定义ALC并加载程序集 var context = new AssemblyLoadContext(directoryInfo.FullName, true); var assembly = context.LoadFromAssemblyPath(fileInfo.FullName); // 使用自定义Catalog var catalog = new AlcCompatibleAssemblyCatalog(assembly); var container = new CompositionContainer(catalog); // 获取导出部件 var plugins = container.GetExportedValues<IMyPlugin>();
注意事项
- 确保插件程序集中的目标类型已正确标记
[Export]属性(对应你使用的MEF版本)。 - 自定义ALC需加载插件的所有依赖程序集,否则扫描类型时会抛出找不到依赖的异常。
- 卸载ALC前,务必释放所有从容器获取的插件实例及容器本身,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Eleasar
相关产品推荐
相关产品推荐

