[英]MEF DirectoryCatalog not override the Project References at time of Loading
我有一个如下界面:
namespace Contract
{
[InheritedExport(typeof(ITransform))]
public interface ITransform
{
string process(string name);
}
}
现在,我有两节课:
using Contract;
namespace ProjectA
{
public class ProjectA:ITransform
{
public string process(string name)
{
ProjectXYZ.ProjectXYZ obj = new ProjectXYZ.ProjectXYZ();
return obj.process("Project A calling");
}
}
}
和
using Contract;
namespace ProjectB
{
public class Datawarehouse:ITransform
{
public string process(string name)
{
ProjectXYZ.ProjectXYZ obj = new ProjectXYZ.ProjectXYZ();
return obj.process("Project B calling");
}
}
}
我有另一个项目ProjectXYZ(由第三方工具(Altova Mapforce 2012 SP1自动生成))。
对于来自altova mapforce 2012的ProjectA定制自动生成的代码:
namespace ProjectXYZ
{
public class ProjectXYZ
{
public string process(string name)
{
name = "This is for Project A :: "+name;
return name;
}
}
}
对于altova mapforce 2012中ProjectB定制的自动生成的代码:
namespace ProjectXYZ
{
public class ProjectXYZ
{
public string process(string name)
{
string n = "This is for Project B ::"+Result();
return n;
}
public string Result()
{
int op1 = 1;
int op2 = op1+3;
return op2.ToString();
}
}
}
不会自动导出第三方自动生成的代码,但是我将其二进制文件用作ProjectA.Transform和ProjectB.Transform的引用。因此,我正在使用[DirectoryCatalog]将所有ProjectA.Transform和ProjectB.Transform二进制文件加载到MEF的CompositionContainer中。 编译每个项目,并将其二进制文件(生成输出)位置作为DirectoryCatalog的输入
为进一步的组成。
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition;
namespace AppConsole
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
public void Run() {
List<string> extensionPath = new List<string>();
//Change the extension Path
extensionPath.Add(@"E:\MEF\MEFForProjectA\ProjectA\bin\Debug");
extensionPath.Add(@"E:\MEF\MEFForProjectB\ProjectB\bin\Debug");
foreach (var extension in extensionPath)
{
ITransform transform = GetExtension(extension);
Console.WriteLine("Extension Loaded :{0}", transform.process(extension));
}
Console.ReadLine();
}
private ITransform GetExtension(string extensionPath)
{
IEnumerable<ITransform> extensions = null;
try
{
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(extensionPath));
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(catalog);
extensions = container.GetExportedValues<ITransform>();
return extensions.FirstOrDefault();
}
catch (Exception ex) { Console.WriteLine(ex.Message); }
return extensions.FirstOrDefault();
}
}
}
ProjectA.Transform使用ProjectXYZ.ClassA,而ProjectB.Transform使用另一个ProjectXYZ实现的ProjectXYZ.ClassB。 实现和类
对于ITransform的不同实现,ProjectXYZ的数量会有所不同。 ProjectXYZ中的类是通过一些第三方工具自动生成的,
需要直接使用。 因此,我无法对ProjectXYZ进行任何更改。
因此,当MEF首次加载ProjectA.Transform时,它还将同时加载ProjectXYZ以用作ProjectA的参考。 当ProjectB.Transform加载/导出时,
然后,因为ProjectXYZ程序集已经在MEF内存中,它使用可从“ C:\\ ProjectDemo \\ ProjectA.Transform \\ Bin \\ Debug”获得的ProjectXYZ程序集引用。 因此,当执行ProjectB.Transform时,它将从“ C:\\ ProjectDemo \\ ProjectB.Transform \\ Bin \\ Debug”中搜索ProjectXYZ程序集,因为MEF已加载了“ C:\\ ProjectDemo \\ ProjectA.Transform \\ Bin \\ Debug” 。
如何解决这个问题。 MEF正确加载了零件,但没有以期望的方式加载支持dll的引用。 我也尝试过
PartCreationPolicy属性,但结果相同。
Expected Result :
Extension Loaded :This is for Project A :: Project A calling
Extension Loaded :This is for Project B :: 4
Actual Result:
Extension Loaded :This is for Project A :: Project A calling
Extension Loaded :This is for Project A :: Project B calling
我认为这是元数据的情况。 MEF无法确定要使用哪个ITransform
实例,因为您始终使用GetExportedValues<ITransform>().FirstOrDefault()
。 如果您向零件提供元数据,例如:
首先,定义元数据接口:
public interface ITransformMetadata
{
string Name { get; }
}
还有一个自定义导出属性:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false), MetadataAttribute]
public class ExportTransformAttribute : ExportAttribute, ITransformMetadata
{
public ExportTransformAttribute(string name)
: base(typeof(ITransform))
{
Name = name;
}
public string Name { get; set; }
}
然后,您可以开始使用其他元数据来丰富您的导出,以后您可以查询这些元数据,例如:
[ExportTransform("ClassB")]
public class ClassBTransform : ITransform { }
并带有查询:
var part = container.GetExports<ITransform, ITransformMetadata>()
.Where(e => e.Metadata.Name.Equals("value"))
.FirstOrDefault();
return part.Value;
编辑 :导出类型时,会提供一条特殊的元数据,称为ExportTypeIdentity,它使用名称空间+导出类型的名称。
在代码中,两个程序集上有两个部分,它们具有相同的名称空间和名称。 ProjectXYZ.ProjectXYZ。 将其与您的FirstOrDefault结合在一起可能是您的问题。
这不是MEF问题。 问题出在.NET的加载模型中。 (或者更好的.net加载对象的方式)
当MEF加载时,它返回正确的对象。 但是当在加载projectB时查找类ProjectXYZ时,已经有一个ProjectXYZ dll加载了正确的程序集名称projectB所引用。 并且加载程序projectB实际引用的dll不会加载。
您只需将添加文件夹的顺序更改为
extensionPath.Add(@“ E:\\ MEF \\ MEFForProjectB \\ ProjectB \\ bin \\ Debug”); extensionPath.Add(@“ E:\\ MEF \\ MEFForProjectA \\ ProjectA \\ bin \\ Debug”);
然后你得到
已加载扩展:这是用于项目B :: 4
您遇到的问题的解决方案是重命名程序集。 当所有ProjectXYZ程序集都有自己的文件名时,您将获得预期的结果。
此致Piet
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.