繁体   English   中英

MEF DirectoryCatalog在加载时不会覆盖项目参考

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM