Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   .NET-Framework (managed code) (https://www.delphipraxis.net/79-net-framework-managed-code/)
-   -   MEF: Plugin-Schlittstelle in C#/WPF (https://www.delphipraxis.net/177080-mef-plugin-schlittstelle-c-wpf.html)

Matze 15. Okt 2013 05:33

MEF: Plugin-Schlittstelle in C#/WPF
 
Hallo zusammen,

seit Tagen versuche ich vergebens per MEF (Managed Extensibilty Framework) eine Plugin-Schnittstelle zu realisieren. Die Plugins sind DLLs, die entsprechend geladen werden.

Relativ schön finde ich z.B. dieses Beispiel: http://stevenhollidge.blogspot.de/20...ef-with-c.html

Am Ende des Beitrags lässt sich der Quellcode herunterladen.

Bei mir stimmen alle Pfade und das Programm lässt sich fehlerfrei kompilieren (ich habe es laut Anleitung auch selbst programmiert).
Dennoch findet das Programm an folgender Stelle kein passendes Plugin:
Code:
var catalog = new DirectoryCatalog(@"..\..\..\Plugins");
var container = new CompositionContainer(catalog);
var pluginRepository = new PluginRepository()
{
    CalculationServices = container.GetExportedValues<ICalculationService>()
};
Ich habe es auch mit einem absoluten Pfad versucht. Und
Code:
Directory.GetFiles()
liefert mir auch die korrekten DLLs. D.h. am Pfad kann es nicht liegen.

Leider bleibt "CalculationServices" leer. Eine Fehlermeldung gibt es nicht.
Woran kann es liegen, dass die DLLs nicht als gültiges Plugin erkannt werden?

Auch mit einer zusätzlichen Export-Angabe funktioniert es nicht:
Code:
[Export(typeof(ICalculationService))]
public class Multiply : ICalculationService
{
    public int Calculate(int number1, int number2)
    {
        return number1 * number2;
    }
}
Ich verwende aktuell Microsoft Visual C# 2010 Express unter Windows XP mit .NET 4.0.

Grüße
Matze

Furtbichler 15. Okt 2013 07:48

AW: MEF: Plugin-Schlittstelle in C#/WPF
 
Geht es Dir um genau diese Lösung, oder irgend eine?

Dann versuch das hier:
1. Das Plugin-Interface IPlugin. Wird von jedem Plugin implementiert. Pro Assembly ein Plugin. Du kannst auch mehrere dort implementieren, aber dann funktioniert der Wrapper weiter unten nicht (kann aber erweitert werden).
Code:
public interface IPlugin
{
  string GetName();
  string GetDescription();
  string GetVersion();
  UserControl ConfigurationDialog();
  void Execute();
  ...
}
2. Der Plugin-Loader im Hauptprogramm. Sucht nach Assemblies und importiert die, die IPlugin implementieren.
Code:
var directoryInfo = new DirectoryInfo(path);
foreach (var file in directoryInfo.GetFiles("*.dll"))
{
   Wrapper pluginWrapper = new PluginWrapper(file.FullName);
   if (pluginWrapper.IsValid)
   {
     string fullname = pluginWrapper.Instance.GetName() + " " +
                   pluginWrapper.Instance.GetVersion();
      ...          
   }
}
Der Plugin-Wrapper:
Code:
internal class PluginWrapper
{
  private readonly IPlugin _pluginInstance;
  public bool IsValid;

  public PluginWrapper(string fullFilename)
  {
    IsValid = false;
    Assembly assembly = Assembly.LoadFile(fullFilename);
    var type = assembly.GetTypes().FirstOrDefault(IsPlugin);
    if (type == null)
      return;
   
    _pluginInstance = (IPlugin)Activator.CreateInstance(type);
    IsValid = true;
  }

  public IPlugin Instance { get { return _pluginInstance; } }

  private bool IsPlugin(Type type)
  {
    return type.IsClass && type.IsPublic && type.GetInterfaces().Contains(typeof(IPlugin));
  }
}
Ein Wrapper wird also mit dem vollständigen Pfadnamen der Assembly instantiiert. Der Wrapper prüft, ob eine IPlugin - Klasse in der Assembly vorhanden ist und setzt 'IsValid' auf true, wenn dem so ist. Dann ist über die Property 'Instance' auch eine Instanz der Implementierung abrufbar.

In dieser Implementierung wird nur die erste IPlugin-Klasse jeder Assembly geladen. Man kann das natürlich erweitern, sodaß alle Klassen geladen werden.

Wie Du siehst, habe ich keinerlei Attribute.

Ich muß aber ehrlich sagen, daß das so mit mein erstes C#-Projekt war, also kann man das bestimmt noch verbessern.

Matze 15. Okt 2013 10:33

AW: MEF: Plugin-Schlittstelle in C#/WPF
 
Dankeschön, das teste ich mal. :-)

Es wäre jedenfalls wichtig, dass man auch mehrere Plugins parallel laden und nutzen kann.

Ich habe im Internet auch ähnliche Lösungen gefunden, nur wurde dann immer auf MEF hingewiesen und dass man damit flexibler sei. Selbst beurteilen kann ich das jedoch nicht.

Grüße
Matze

Elvis 15. Okt 2013 18:07

AW: MEF: Plugin-Schlittstelle in C#/WPF
 
Hassu einmal Build Solution [F6] ausgeführt?
Der Auto hat die Plugins nicht als indirekte Dependencies von MefSimpleDemo eingetragen. MsBuild weiß also gar nicht, dass es die 2 anderen Projekte auch kompostieren muss, wenn es MefSimpleDemo kompiliert.

Furtbichler 15. Okt 2013 18:55

AW: MEF: Plugin-Schlittstelle in C#/WPF
 
Zitat:

Zitat von Matze (Beitrag 1232065)
Es wäre jedenfalls wichtig, dass man auch mehrere Plugins parallel laden und nutzen kann.

Natürlich.

Matze 16. Okt 2013 05:55

AW: MEF: Plugin-Schlittstelle in C#/WPF
 
Zitat:

Zitat von Elvis (Beitrag 1232109)
Hassu einmal Build Solution [F6] ausgeführt?

Ja, habe ich gemacht. Ich habe jede Klassenbibliothek etc. auch mal manuell kompiliert und die DLLs wurden angelegt.

Elvis 16. Okt 2013 11:48

AW: MEF: Plugin-Schlittstelle in C#/WPF
 
Zitat:

Zitat von Matze (Beitrag 1232136)
Zitat:

Zitat von Elvis (Beitrag 1232109)
Hassu einmal Build Solution [F6] ausgeführt?

Ja, habe ich gemacht. Ich habe jede Klassenbibliothek etc. auch mal manuell kompiliert und die DLLs wurden angelegt.

Hast du die Dateien vllt im Netzwerk liegen? .Net ist zwar mittlerweile weniger zickig was das Intranet angeht, aber immer noch zickig genug um ab & zu zu nerven.

Ungeachtet dessen...

Ich habe das:
Runtergeladen -> Entpackt -> im VS geöffnet -> F5 -> ging nicht -> F6 -> F5 -> funzt

Benutzt du C# Express? Da ist es etwas schwierig die Build-Configs zu verwalten.
IMO wird dort ein Build als Release kompiliert und jeder Debug-Run mit der Debug Config. (Komplett Ouchy-Banana, aber mit irgendwelchen blöden Einschränkungen müssen sie einem ja die kostenlose IDE versalzen ;-) )
Das könnte erklären, warum es bei dir nicht geht.
Du kannst es per commandline kompilieren...
Code:
msbuild MefSimpleDemo.sln /t:Rebuild /p:Configuration=Debug
oder die Ausgabepfade in den beiden Projekten anpassen.

Matze 16. Okt 2013 14:25

AW: MEF: Plugin-Schlittstelle in C#/WPF
 
Zitat:

Zitat von Elvis (Beitrag 1232169)
Benutzt du C# Express? Da ist es etwas schwierig die Build-Configs zu verwalten.
IMO wird dort ein Build als Release kompiliert und jeder Debug-Run mit der Debug Config.

Jupp. Puh das ist dann aber umständlich. Aber ich kann's versuchen ...
Ich kann mit C# Express schon ein Release-Build generieren, aber der wird nicht als gültige DLL akzeptiert, wie's aussieht.

Elvis 16. Okt 2013 21:41

AW: MEF: Plugin-Schlittstelle in C#/WPF
 
Nein Release builds haben eine andere Konfiguration. Also auch einen anderen Ausgabepfad.
Du kannst auch #develop nehmen, das ist nicht so bescheuert wie c# express.

Matze 17. Okt 2013 05:48

AW: MEF: Plugin-Schlittstelle in C#/WPF
 
Danke. Dann teste ich, ob es mit #develop funktioniert.

Kennst du dennoch eine Möglichkeit, das ganze mit Visual C# Express zum Laufen zu bekommen? Vielleicht liegt's nur an einer Einstellung.

Nachtrag: Mit #develop ist's das Gleiche. :gruebel:
Mir wäre Visual C# Express aber lieber.

Nachtrag 2: Ich Duppel. Es funktioniert alles. Das Stichwort "Netzwerk" war der Knackpunkt. Ich nutze eine Virtual Machine und greife über Shared Folders auf den Host zu. Und diese Verzeichnisse werden als Netzlaufwerk eingebunden und darin lag mein Projekt. :wall:
Da wäre eine Warnung des Debuggers o.ä. eigentlich angebracht ...

Nochmals vielen Dank euch beiden!


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:48 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz