MEF DirectoryCatalog не переопределяет ссылки проекта во время загрузки - PullRequest
0 голосов
/ 27 марта 2012

У меня интерфейс выглядит следующим образом:

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)).

Для настроенного AutoA автоматически сгенерированного кода из Altova mapforce 2012:

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

Для настраиваемого ProjectB автоматически сгенерированного кода из altova mapforce2012:

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 в CompositionContainer 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.ClassB из другой реализации ProjectXYZ.Реализация и классы

ProjectXYZ различаются для разных реализаций ITransform.Классы в ProjectXYZ автоматически генерируются с помощью некоторых сторонних инструментов, которые мне

нужно использовать напрямую.Поэтому я не могу вносить какие-либо изменения в ProjectXYZ.

Поэтому, когда MEF впервые загружает ProjectA.Transform, он также загружает ProjectXYZ для использования в качестве ссылки для ProjectA.Когда ProjectB.Transform загружается / экспортируется,

, тогда как сборки ProjectXYZ уже находятся в памяти MEF, он использует ссылку на сборки ProjectXYZ, доступную из "C: \ ProjectDemo \ ProjectA.Transform \ Bin \ Debug«.Таким образом, когда выполняется ProjectB.Transform, он ищет сборки ProjectXYZ из "C: \ ProjectDemo \ ProjectB.Transform \ Bin \ Debug" , которые он не получает, поскольку 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

Ответы [ 2 ]

0 голосов
/ 29 марта 2012

Это не проблема MEF.Проблема в загрузочной модели .NET.(или лучше то, как вы загружаете объекты с помощью .net)

Когда MEF загружает, он возвращает правильные объекты.Но при поиске класса ProjectXYZ при загрузке projectB уже есть dll ProjectXYZ, загруженная с правильным именем сборки, на которое ссылается projectB.И загрузчик библиотеки DLL, на которую фактически ссылается projectB, не загружен.

Вы можете попробовать сами, просто изменив последовательность добавленных папок на

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

Тогда вы получите

Расширение загружено: это для проекта B: 4 Расширение загружено:Это для проекта B :: 4

Решение вашей проблемы - переименование сборки.Когда у всех сборок ProjectXYZ есть собственное имя файла, вы получите ожидаемый результат.

С уважением, Пит

0 голосов
/ 27 марта 2012

Я думаю, что это относится к метаданным. MEF не может определить, какой экземпляр ITransform использовать, потому что вы всегда используете GetExportedValues<ITransform>().FirstOrDefault(). Если вы предоставили метаданные для ваших частей, например ::100100

Во-первых, определите интерфейс метаданных:

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;

edit : когда экспортируется тип, предоставляется специальный фрагмент метаданных, называемый ExportTypeIdentity, который использует пространство имен + имя экспортируемого типа.

В вашем коде у вас две части на двух сборках с одинаковым пространством имен и именем. ProjectXYZ.ProjectXYZ. Сочетание этого с FirstOrDefault, вероятно, станет вашей проблемой.

...