.NET 6 WPF Hybrid迁移中MEF的ImportMany无法工作求助
问题描述
我正在将.NET Framework 4.6.2下的代码迁移至.NET 6 WPF Hybrid应用,使用MEF框架。容器已加载插件及元数据,但通过[ImportMany]标记的两个集合均为空,且未抛出任何异常。该插件在.NET Framework应用中可正常加载,求解决ImportMany无法工作的问题。
相关代码
PluginHandler类
public class PluginHandler { [ImportMany(typeof(IKapprisWebViewerClientPlugin))] private static IEnumerable<Lazy<IKapprisWebViewerClientPlugin, IKapprisWebViewerClientPluginData>>? plugins { get; set; } = new List<Lazy<IKapprisWebViewerClientPlugin, IKapprisWebViewerClientPluginData>>(); [ImportMany(typeof(IKapprisWebViewerClientPlugin))] private static IEnumerable<IKapprisWebViewerClientPlugin>? plugins1 { get; set; } = new List<IKapprisWebViewerClientPlugin>(); public PluginHandler() { //An aggregate catalog that combines multiple catalogs var catalog = new AggregateCatalog(); string exePath = System.Reflection.Assembly.GetExecutingAssembly().Location; string directory = new Uri(Path.GetDirectoryName(exePath)).LocalPath; //Adds all the parts found in all assemblies in //the same directory as the executing program catalog.Catalogs.Add( new DirectoryCatalog( directory, "kwc*.dll")); //Create the CompositionContainer with the parts in the catalog CompositionContainer container = new CompositionContainer(catalog); //Fill the imports of this object container.ComposeParts(this); //container.SatisfyImportsOnce(this); } }
插件类与元数据接口
[Export(typeof(IKapprisWebViewerClientPlugin))] [ExportMetadata("Name", "IManage 10 / Cloud")] public class WebViewerIntegration : WebViewerClientPlugin { ... } public interface IKapprisWebViewerClientPluginData { /// <summary> /// Name used to identify plugin /// </summary> string Name { get; } }
解决步骤
检查MEF包版本
.NET 6需使用System.ComponentModel.CompositionNuGet包,而非.NET Framework自带的MEF组件。确保项目已安装正确版本:执行Install-Package System.ComponentModel.Composition,避免混用旧版本组件。修正静态成员的导入问题
MEF默认不支持导入静态属性,因为ComposeParts/SatisfyImportsOnce仅作用于实例对象,静态成员不在实例导入范围内。将两个集合改为非静态属性:[ImportMany(typeof(IKapprisWebViewerClientPlugin))] private IEnumerable<Lazy<IKapprisWebViewerClientPlugin, IKapprisWebViewerClientPluginData>>? plugins { get; set; } = new List<Lazy<IKapprisWebViewerClientPlugin, IKapprisWebViewerClientPluginData>>(); [ImportMany(typeof(IKapprisWebViewerClientPlugin))] private IEnumerable<IKapprisWebViewerClientPlugin>? plugins1 { get; set; } = new List<IKapprisWebViewerClientPlugin>();验证元数据接口匹配性
确保元数据接口IKapprisWebViewerClientPluginData被MEF正确识别:- 接口必须是公共(public)的,且属性名称与
ExportMetadata的键完全一致(此处为"Name")。 - 可通过自定义元数据属性增强识别性:
插件类改用自定义属性替代原有[MetadataAttribute] [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class KapprisWebViewerClientPluginDataAttribute : ExportAttribute, IKapprisWebViewerClientPluginData { public string Name { get; } public KapprisWebViewerClientPluginDataAttribute(string name) : base(typeof(IKapprisWebViewerClientPlugin)) { Name = name; } }Export和ExportMetadata:[KapprisWebViewerClientPluginData("IManage 10 / Cloud")] public class WebViewerIntegration : WebViewerClientPlugin { // ... }
- 接口必须是公共(public)的,且属性名称与
确认插件程序集加载路径
.NET 6中Assembly.GetExecutingAssembly().Location的返回路径可能与.NET Framework不同(比如单文件发布场景),改用AppContext.BaseDirectory获取应用根目录:string directory = AppContext.BaseDirectory;同时验证
kwc*.dll是否存在于该目录,或指定完整路径排查加载问题。启用MEF调试验证
添加代码查看容器加载的部件,确认插件是否被正确识别:var parts = catalog.Parts.ToList(); foreach (var part in parts) { Console.WriteLine($"Loaded part: {part.ToString()}"); }若未加载到插件,检查插件目标框架是否与主应用兼容(建议编译为.NET Standard 2.0或.NET 6),且无缺失依赖项。
更换导入方法
尝试将container.ComposeParts(this)替换为container.SatisfyImportsOnce(this),后者更适合一次性导入场景,避免潜在的部件重复组合问题。
内容的提问来源于stack exchange,提问作者user2903089

