0

我有一个界面如下:

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。实现和类

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 已加载"C:\ProjectDemo\项目A.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
4

2 回答 2

0

这不是 MEF 问题。问题出在 .NET 的加载模型中。(或者更好的方式是你的对象由.net加载)

当 MEF 加载时,它会返回正确的对象。但是,在加载 projectB 时查找类 ProjectXYZ 时,已经有一个 ProjectXYZ dll 加载了正确的程序集名称 projectB 所指的。并且没有加载projectB实际引用的dll的loader。

您可以通过将添加文件夹的顺序更改为

extensionPath.Add(@"E:\MEF\MEFForProjectB\ProjectB\bin\Debug"); extensionPath.Add(@"E:\MEF\MEFForProjectA\ProjectA\bin\Debug");

然后你得到

已加载扩展:这是针对项目 B :: 4 已加载扩展:这是针对项目 B :: 4

您问题的解决方案是重命名程序集。当所有 ProjectXYZ 程序集都有自己的文件名时,您会得到预期的结果。

问候,皮特

于 2012-03-28T21:10:29.447 回答
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,它使用命名空间 + 导出类型的名称。

在您的代码中,您在两个程序集中有两个部件,具有相同的命名空间和名称。项目XYZ.项目XYZ。将它与您的 FirstOrDefault 结合起来可能是您的问题。

于 2012-03-27T16:42:49.867 回答