2013-10-24 1 views
5

Я пытаюсь добавить расширяемость плагина к моему приложению C# с использованием рамки Managed Extensibility Framework (MEF), и пока все идет нормально; У меня есть приложение для основного/хоста, загружающее плагины из определенной папки и вызывая их методы и т. Д. Из основного приложения. И приложение-хост, и плагины ссылаются на отдельную сборку dll, которая содержит интерфейсы, общие для всех проектов.Использование MEF с C#, как мне вызвать методы на хосте, из плагина?

Это нормально работает, и я могу звонить/взаимодействовать с плагинами из основного приложения. Тем не менее, я также хотел бы иметь возможность взаимодействовать с хост-приложением от плагинов, но, похоже, не может понять, как это делается.

Я хотел бы иметь возможность получить/установить/выполнить экспортированные свойства и методы в основном приложении из моих плагинов. В настоящее время я могу только «говорить» с плагинами из основного приложения, а не наоборот.

Мой код до сих пор:

Интерфейс DLL

namespace MefContracts 
{ 
    [InheritedExport] 
    public interface IPlugin 
    { 
     String DoWork(); 
    } 

    public class Class1 
    { 
     public IPlugin plugin { get; set; } 
    } 
} 

Главная/Хост Применение

namespace MyMEF 
{ 
    class clsMEF 
    { 
     private CompositionContainer _container; 

     [Import(typeof(MefContracts.IPlugin))] 
     public MefContracts.IPlugin plugin; 

     public clsMEF() 
     { 
      Compose(); 
     } 

     void Compose() 
     { 
      var catalog = new AggregateCatalog(); 
      catalog.Catalogs.Add(new DirectoryCatalog("..\\..\\Extensions")); 
      _container = new CompositionContainer(catalog); 
      try 
      { 
       this._container.ComposeParts(this); 
      } 
      catch (CompositionException compositionException) 
      { 
       Console.WriteLine(compositionException.ToString()); 
      } 
     } 
    } 

    void Main() 
    { 
     clsMEF myMef = new clsMEF(); 
     MessageBox.Show(myMef.plugin.DoWork()); 
    } 
} 

Плагин

namespace MefPlugin 
{ 
    [Export] 
    public class Class1 : MefContracts.IPlugin 
    { 

     public String DoWork() 
     { 
      return "Plugin called"; 
     } 
    } 
} 

ответ

3

После долгих игр, проб и ошибок, я обнаружил, что проблема связана с тем, что я не добавил текущую сборку (System.Reflection.Assembly.GetExecutingAssembly()) в каталог сборки узла вместе с сборки плагинов.

Огромное спасибо @PanosRontogiannis, который получил меня на правильных строках - этот ответ блестяще работал, как только сборка была правильно добавлена.

Вот рабочий код для других нуждающихся:

интерфейса DLL

using System.ComponentModel.Composition; 

namespace MefContracts 
{ 
    [InheritedExport] 
    public interface IPlugin 
    { 
     String Work(String input); 
    } 

    [InheritedExport] 
    public interface IHost 
    { 
     string Version { get; } 
    } 
} 

Хост Применение

using System.ComponentModel.Composition; 
using System.ComponentModel.Composition.Hosting; 

namespace MyMEF 
{ 

    [Export] 
    public class Class1 : MefContracts.IHost 
    { 
     public String Version 
     { 
      get { return "v1.00"; } 
     } 
    } 

    class clsMEF 
    { 
     private CompositionContainer _container; 

     [Import(typeof(MefContracts.IPlugin))] 
     public MefContracts.IPlugin plugin; 

     public clsMEF() 
     { 
      Compose(); 
     } 

     void Compose() 
     { 
      var catalog = new AggregateCatalog(); 
      catalog.Catalogs.Add(new DirectoryCatalog("..\\..\\Extensions")); 
      catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly())); // <-- THIS WAS THE MISSING PIECE 
      _container = new CompositionContainer(catalog); 
      try 
      { 
       this._container.ComposeParts(this); 
      } 
      catch (CompositionException compositionException) 
      { 
       Console.WriteLine(compositionException.ToString()); 
      } 

     } 
    } 
    static class Program 
    { 
     static void Main() 
     { 
      clsMEF myMef = new clsMEF(); 
      MessageBox.Show(myMef.plugin.Work("My Input")); 
     } 
    } 
} 

Plugin

using System.ComponentModel.Composition; 

namespace MefPlugin 
{ 
    [Export] 
    public class Class2 : MefContracts.IPlugin 
    { 
     [Import(typeof(MefContracts.IHost))] 
     public MefContracts.IHost Host; 

     public String Work(String input) 
     { 
      return "Plugin Called (Input: " + input + "). Host Application Version: " + input + Host.Version; 
     } 
    } 
} 
+0

Мой принимающий член никогда не заселен. Вы когда-нибудь сталкивались с этим? – jsmith

+0

@jsmith - Извините за поздний ответ, но я думаю, что это была первая проблема, с которой я столкнулся в это время. Если вы еще не решили это и хотели бы опубликовать свой код по другому вопросу и ссылке, я с удовольствием посмотрю. – Alfie

4

Вы можете добавить интерфейс хоста в сборку контрактов. Например:

[InheritedExport] 
public interface IHost 
{ 
    string Version { get; } 
} 

Затем добавить свойство типа IHost к интерфейсу IPlugin:

[InheritedExport] 
public interface IPlugin 
{ 
    IHost Host { get; } 
    String DoWork(); 
} 

Наконец каждый плагин нужно будет украсить свойство хоста с ImportAttribute MEF в:

[Import(typeof(IHost))] 
public IHost Host { get; } 
+0

Благодарим вас за ответ.Я только что пошел с этим, но, к сожалению, без успеха (никаких ошибок, просто ничего не получаю). Думаю, я должен что-то упустить; Какова правильная реализация IHost в хост-приложении? как он должен быть выставлен? – Alfie