简体   繁体   English

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

[英]MEF DirectoryCatalog not override the Project References at time of Loading

I have a interface as follows: 我有一个如下界面:

namespace Contract
{
    [InheritedExport(typeof(ITransform))]
    public interface ITransform
    {
       string process(string name);
    }
}

Now, I have two classes: 现在,我有两节课:

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");
        }
    }
}

And

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");
        }
    }
}

I have another project ProjectXYZ(auto generated by third party tool(Altova Mapforce 2012 SP1)). 我有另一个项目ProjectXYZ(由第三方工具(Altova Mapforce 2012 SP1自动生成))。

For ProjectA customized auto generated code from altova mapforce 2012: 对于来自altova mapforce 2012的ProjectA定制自动生成的代码:

namespace ProjectXYZ
{
    public class ProjectXYZ
    {
        public string process(string name)
        {
            name = "This is for Project A :: "+name;
            return name;
        }
    }
}

For ProjectB customized auto generated code from altova mapforce 2012: 对于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();
        }
    }
}

Third party auto generated codes are not exported, But its binaries I used as reference of ProjectA.Transform and ProjectB.Transform.So I am using [DirectoryCatalog] for loading all binaries of ProjectA.Transform and ProjectB.Transform in CompositionContainer of MEF. 不会自动导出第三方自动生成的代码,但是我将其二进制文件用作ProjectA.Transform和ProjectB.Transform的引用。因此,我正在使用[DirectoryCatalog]将所有ProjectA.Transform和ProjectB.Transform二进制文件加载到MEF的CompositionContainer中。 Each project is compiled and their binaries(build output) location is given as an input to DirectoryCatalog 编译每个项目,并将其二进制文件(生成输出)位置作为DirectoryCatalog的输入

for further composition. 为进一步的组成。

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 uses ProjectXYZ.ClassA, whereas ProjectB.Transform uses ProjectXYZ.ClassB from another implementation of ProjectXYZ. ProjectA.Transform使用ProjectXYZ.ClassA,而ProjectB.Transform使用另一个ProjectXYZ实现的ProjectXYZ.ClassB。 The implementation and classes 实现和类

of ProjectXYZ varies across for different implementation of ITransform. 对于ITransform的不同实现,ProjectXYZ的数量会有所不同。 The classes in ProjectXYZ are automatically generated through some third-party tools, which I ProjectXYZ中的类是通过一些第三方工具自动生成的,

need to use directly. 需要直接使用。 So, I cannot make any changes to ProjectXYZ. 因此,我无法对ProjectXYZ进行任何更改。

So, when first time MEF loads ProjectA.Transform, it also loads ProjectXYZ to be used as a reference for ProjectA. 因此,当MEF首次加载ProjectA.Transform时,它还将同时加载ProjectXYZ以用作ProjectA的参考。 When ProjectB.Transform is getting loaded/exported, 当ProjectB.Transform加载/导出时,

then as ProjectXYZ Assemblies being already in MEF memory, it uses the ProjectXYZ Assemblies reference available from "C:\\ProjectDemo\\ProjectA.Transform\\Bin\\Debug" . 然后,因为ProjectXYZ程序集已经在MEF内存中,它使用可从“ C:\\ ProjectDemo \\ ProjectA.Transform \\ Bin \\ Debug”获得的ProjectXYZ程序集引用。 Thus, when ProjectB.Transform is executing, it searches for ProjectXYZ Assemblies from "C:\\ProjectDemo\\ProjectB.Transform\\Bin\\Debug" , which it does not gets as MEF has load ProjectXYZ Assemblies reference available in "C:\\ProjectDemo\\ProjectA.Transform\\Bin\\Debug" . 因此,当执行ProjectB.Transform时,它将从“ C:\\ ProjectDemo \\ ProjectB.Transform \\ Bin \\ Debug”中搜索ProjectXYZ程序集,因为MEF已加载了“ C:\\ ProjectDemo \\ ProjectA.Transform \\ Bin \\ Debug”

How to resolve this problem. 如何解决这个问题。 The MEF loads the parts correctly, but it does not load the supporting dll's references in a desired manner. MEF正确加载了零件,但没有以期望的方式加载支持dll的引用。 I have also tried 我也尝试过

PartCreationPolicy attribute, but the results are same. 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

I think this would be a case for metadata. 我认为这是元数据的情况。 MEF can't determine which instance of ITransform to use, because you are always using GetExportedValues<ITransform>().FirstOrDefault() . MEF无法确定要使用哪个ITransform实例,因为您始终使用GetExportedValues<ITransform>().FirstOrDefault() If you supplied metadata to your parts, eg: 如果您向零件提供元数据,例如:

Firstly, define a metadata interface: 首先,定义元数据接口:

public interface ITransformMetadata
{
    string Name { get; }
}

And a custom export attribute: 还有一个自定义导出属性:

[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; }
}

You can then start enriching your exports with additional metadata, which you can later query, eg: 然后,您可以开始使用其他元数据来丰富您的导出,以后您可以查询这些元数据,例如:

[ExportTransform("ClassB")]
public class ClassBTransform : ITransform { }

And with a query: 并带有查询:

var part = container.GetExports<ITransform, ITransformMetadata>()
    .Where(e => e.Metadata.Name.Equals("value"))
    .FirstOrDefault();
return part.Value;

edit : when a type is exported, a special piece of metadata is provided, called an ExportTypeIdentity, which uses the namespace + name of the exported type. 编辑 :导出类型时,会提供一条特殊的元数据,称为ExportTypeIdentity,它使用名称空间+导出类型的名称。

In your code, you have two parts on two assemblies, with the same namespace and name. 在代码中,两个程序集上有两个部分,它们具有相同的名称空间和名称。 ProjectXYZ.ProjectXYZ. ProjectXYZ.ProjectXYZ。 Combining that with your FirstOrDefault is likely to be your problem. 将其与您的FirstOrDefault结合在一起可能是您的问题。

It not a MEF problem. 这不是MEF问题。 The problem is in the loading model of .NET. 问题出在.NET的加载模型中。 (or better the way you're objects are loaded by .net) (或者更好的.net加载对象的方式)

When MEF loads it returns the correct objects. 当MEF加载时,它返回正确的对象。 But when looking for class ProjectXYZ when projectB is loaded there is already a ProjectXYZ dll loaded with the correct assembly name projectB is referring to. 但是当在加载projectB时查找类ProjectXYZ时,已经有一个ProjectXYZ dll加载了正确的程序集名称projectB所引用。 And the loader the dll actually referenced by projectB is not loaded. 并且加载程序projectB实际引用的dll不会加载。

You can try it you're self just by changing the sequence of the added folders into 您只需将添加文件夹的顺序更改为

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

Then you get 然后你得到

Extension Loaded :This is for Project B :: 4 Extension Loaded :This is for Project B :: 4 已加载扩展:这是用于项目B :: 4

The solution to you're problem is renaming the assembly. 您遇到的问题的解决方案是重命名程序集。 When all ProjectXYZ assemblies have there own filename you get the expected result. 当所有ProjectXYZ程序集都有自己的文件名时,您将获得预期的结果。

Regards, Piet 此致Piet

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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