我有一个如下界面:
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]在CompositionContainer中加载ProjectA.Transform和ProjectB.Transform的所有二进制文件。 MEF。编译每个项目,并将其二进制文件(构建输出)位置作为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。实现和类
ProjectXYZ的因ITransform的不同实现而异。 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已加载ProjectXYZ程序集参考,所以它不会获取在“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
答案 0 :(得分:0)
我认为这是元数据的一种情况。 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相结合可能是您的问题。
答案 1 :(得分:0)
这不是MEF问题。问题出在.NET的加载模型中。 (或者更好的是你的对象被.net加载的方式)
当MEF加载时,它返回正确的对象。但是当在加载projectB时查找类ProjectXYZ时,已经有一个ProjectXYZ dll加载了projectB引用的正确程序集名称。并且没有加载projectB实际引用的dll加载器。
您可以通过将添加的文件夹的顺序更改为
来尝试自己extensionPath.Add(@ “E:\ MEF \ MEFForProjectB \项目B \ BIN \调试”); extensionPath.Add(@ “E:\ MEF \ MEFForProjectA \项目A \ BIN \调试”);
然后你得到
扩展已加载:这适用于项目B :: 4 Extension Loaded:这是Project B :: 4
解决问题的方法是重命名程序集。当所有ProjectXYZ程序集都有自己的文件名时,您将获得预期的结果。
此致 皮特