2013-10-24 5 views
5

Ich versuche, Plugin-Erweiterbarkeit zu meiner C# -Anwendung mit dem Managed Extensibility Framework (MEF) Framework hinzufügen, und bis jetzt ist es in Ordnung; Ich habe meine Haupt/Host-Anwendung laden Plugins aus einem definierten Ordner und kann ihre Methoden usw. aus der Hauptanwendung aufrufen. Sowohl die Host-Anwendung als auch die Plugins verweisen auf eine separate DLL-Assembly, die die für alle Projekte gemeinsamen Schnittstellen enthält.Mit MEF mit C#, wie rufe ich Methoden auf dem Host, vom Plugin?

Das funktioniert gut und ich kann mit den Plugins aus der Hauptanwendung aufrufen/interagieren. Allerdings möchte ich auch mit der Host-Anwendung von die Plugins interagieren können, aber kann nicht herausfinden, wie dies getan wird.

Ich möchte exportierte Eigenschaften und Methoden in der Hauptanwendung von meinen Plugins erhalten/setzen/ausführen lassen. Momentan kann ich nur mit den Plugins von der Haupt-App "sprechen", nicht umgekehrt.

Mein Code so weit:

Schnittstelle DLL

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

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

Main/Host-Anwendung

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

Plugin

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

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

Antwort

3

Nach viel Spiel und Versuch und Irrtum, fand ich das Problem, das ich hatte, hatte ich nicht die aktuelle ausführende Assembly (System.Reflection.Assembly.GetExecutingAssembly()) zum Assembly-Katalog des Hosts zusammen mit der hinzugefügt Plug-in-Baugruppen.

Vielen Dank an @PanosRontogiannis, die mich auf die richtige Linie gebracht haben - diese Antwort funktionierte hervorragend, sobald die Baugruppe richtig hinzugefügt wurde.

Hier ist der Arbeitscode für andere in Not:

Schnittstelle DLL

using System.ComponentModel.Composition; 

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

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

Host-Anwendung

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

Mein Gastgebermitglied wird nie ausgefüllt. Ist dir das jemals begegnet? – jsmith

+0

@jsmith - Sorry für die späte Antwort, aber ich denke, das war das anfängliche Problem, mit dem ich zu dieser Zeit konfrontiert war. Wenn Sie dies noch nicht gelöst haben und Ihren Code auf eine andere Frage und einen Link hier posten möchten, schaue ich gerne vorbei. – Alfie

4

Sie könnten eine Host-Schnittstelle in der Contracts-Assembly hinzufügen. Zum Beispiel:

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

Dann eine Eigenschaft vom Typ IHost zum IPlugin Schnittstelle hinzufügen:

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

Schließlich jeder Plug-in wird die Host-Eigenschaft mit MEFs ImportAttribute dekorieren müssen:

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

Vielen Dank für Ihre Antwort.Ich habe gerade damit angefangen, aber leider ohne Erfolg (keine Fehler, nur nichts zurückbekommen). Ich denke, ich muss etwas vermissen; Was ist die richtige Implementierung von IHost in der Host-Anwendung? Wie sollte es ausgestellt werden? – Alfie

Verwandte Themen