Laden...

Plugin-Struktur macht Probleme... Typ kann nicht umgewandelt werden

Erstellt von ViperNeo vor 13 Jahren Letzter Beitrag vor 13 Jahren 1.761 Views
V
ViperNeo Themenstarter:in
352 Beiträge seit 2008
vor 13 Jahren
Plugin-Struktur macht Probleme... Typ kann nicht umgewandelt werden

Hallo Leute,

ich habe folgende Situation...

Ich habe eine Klassenbibliothek, die ein Interface für ein Plugin definiert. Diese Bibliothek ist mit einem Strong-Name versehen.

Dann habe ich eine Hauptanwendung, die den Plugin-Service implementiert und die Klassenbibliothek als Verweis beinhaltet. Ebenfalls mit Strong-Name.

Dann habe ich ein Testplugin geschrieben, dass ebenfalls die Klassenbibliothek beinhaltet um von dem Plugin-Interface erben zu können.

So nun habe ich eine Klasse


public class Plugin : IPlugin

Diese versuche ich später dann in der Hauptanwendung über den Plugin-Service zu casten:


newPlugin.Instance = (IPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));

Aber genau hier gehts in die HOse... Ich bekomme ständig die Meldung "Umwandlung des Typs TestPlugin.Plugin in Typ PluginInterface.IPlugin ist nicht möglich".

Wenn ich nun jedoch das Plugin Interface mit in meine Hauptanwendung reinnehme und dann der PluginBibliothek einen Verweis auf die Hauptanwendung verpasse, läuft alles reibungslos. Ich weiß nicht wo da der Wurm drin ist... Hoffe mir kann da jemand vllt die Augen öffnen^^

Grüße ViperNeo

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo ViperNeo,

selbst verständlich muss sowohl Plugin als auch Hauptanwendung dasselbe Interface verwenden. Dazu packst du es am besten in eine eigene DLL.

herbivore

V
ViperNeo Themenstarter:in
352 Beiträge seit 2008
vor 13 Jahren

hm das habe ihc doch getan... beide nutzen die gleiche klassenbibliothek in der das interface definiert ist.

V
ViperNeo Themenstarter:in
352 Beiträge seit 2008
vor 13 Jahren

Hallo,

ich schreibe nochmal was zum genauen Aufbau:

Klassenbibliothek: PluginInterface
Namespace: PluginInterface
Interface: IPlugin, IPluginHost
Signiert mit starkem Namen: Ja

WinForms-Anwendung: PluginTest
Namespace: PluginTest
Klasse: PluginService : IPluginHost
Signiert mit starkem Namen: ja

Klassenbibliothek: MyPlugin
Namespace: Test.MyPlugin
Klasse: MeinErstesPlugin : IPlugin
Signiert: nein

So, die Hauptanwendung und die Pluginbibliothek verweisen beide auf die erste Bibliothek, die die Definition für die Pluginstrukturen beherbergt. Nun bekomme ich folgende Fehlermeldung wenn ich versuche ein Plugin zu laden:
"Typ Test.MyPlugin.MeinErstesPlugin kann nicht in Typ PluginInterface.IPlugin konvertiert werden."

Kann mir jemand erklären was ich übersehe oder nicht verstanden hab?

Danke!

Grüße
ViperNeo

V
ViperNeo Themenstarter:in
352 Beiträge seit 2008
vor 13 Jahren

So, mittlerweile bin ich etwas schlauer geworden...

Und zwar lag es daran, dass das Plugin in einem Unterordner lag und der Bezug zur InterfaceBibliothek nicht da war...

Nun frage ich mich jedoch, wie ich das am geschicktesten löse.

Kopiere ich nun alle Assemblys in das gleiche Verzeichnis funktioniert es problemlos. Lade ich jedoch die Plugins aus einem Unterordner funktioniert es nicht. Verschiebe ich die INterface Bibliothek auch ins UNterverzeichnis geht die Hauptanwendung nicht mehr und habe ich in beiden die gleiche Interface Bibliothek können die Plugins nicht geladen werden, da sie unterschiedliche Interface Bibliothek-Dateien nutzen...

Bin für jeden TIp dankbar!

3.971 Beiträge seit 2006
vor 13 Jahren
  1. Host und Plugin müssen haargenau mit der selben Plugin.dll kompiliert sein. Name, Versionsnummer, Kultur und PublicToken müssen exakt gleich sein.

  2. Wenn du für die Plugins seperate AppDomains verwendet, könntest du direkt beim Erstellen der AppDomain schon die Plugin-Bibliothek in die AppDomain laden, oder aber du verwendest das AssemblyResolveEvent der AppDomain (Stichwort LoadFrom)

Benutzt du keine seperaten AppDomains, verwendest du definiert zwei unterschiedliche Plugin-Bibliotheken.

  1. Gibts bei der Umwandlung eventuell auch eine InnerException?

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

V
ViperNeo Themenstarter:in
352 Beiträge seit 2008
vor 13 Jahren

Also mittlerweile sieht es so aus, dass ich keinen Umwandlungsfehler mehr bekomme, sondern er die PluginAssembly nicht laden kann. Da schmiert Assembly.GetTypes() ab, ich vermute das liegt daran, dass in dem Moment die Referenz auf die Interface Bibliothek nicht da ist.

Beide Projekte werden eigentlich mit der Interface Bibliothek kompiliert als Referenz. Also Punkt 1 sollte gewährleistet sein hoffe ich.

AssemblyResolve verwende ich in der Hauptanwendung, jedoch lässt sich diese nicht starten ohne das die Bibliothek vorhanden ist, da die AssemblyResolve erst gar nicht gefragt wird. Das könnte daran liegen das ich in der Hauptanwendung eine globales Objekt des PluginServices deklariert habe.

Nochmal zum Aufbau:
Hauptanwendung referenziert IPlugin.dll und beinhaltet den PluginServiceProvider.
Plugin referenziert IPlugin.dll und beinhaltet das zu ladende Plugin.
IPlugin definiert das Interface der Plugins und des PluginHosts.

Alle drei sind Projektmappen bei mir.

So, wenn ich nun kompiliere habe ich folgende Dateistruktur zusammenkopiert:
Anwendung.exe
IPlugin.dll
Plugins/Plugin1.dll

Das ist mein Ziel das es läuft. Wenn ich nun die Anwendung starte wird erstmal
Assembly.Load(Plugin/Plugin1.dll) geladen.
Danach werden die Types per Assembly.GetTypes() extrahiert und da knallt es. Kopiere ich nun die Plugin1.dll in das Hauptverzeichnis und lade Plugins daraus funktioniert es prima, also fehlt wohl der Bezug zur IPlugin.dll. Aber ich verstehe nicht wieso. IN jedem Beispiel das ich runterlade ist so eine Struktur problemlos möglich...

Wie sichere ich mich ab, dass beide mit der gleichen DLL kompiliert wurden und das passt. Wie sichere ich das beides in der gleihcen appDomain läuft? Oder wäre es sinnvoll das auf mehrere Auszudehnen? Wenn ja, gibts dafür Beispiele?

DAnke schonmal vielmals!

//edit: Die LoaderException von GetTypes gibt folgende aus:
{"Die Datei oder Assembly "IPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.":"IPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"}

//edit: So nun bin ich mir relativ sicher, dass das kompilat nicht übereinstimmt. weil beim kompilieren von der hauptanwendung die IPlugin.dll neu kompiliert wird... Jetzt mal ne sau blöde frage... Wie stelle ich das ab?

3.971 Beiträge seit 2006
vor 13 Jahren

So nun bin ich mir relativ sicher, dass das kompilat nicht übereinstimmt. weil beim kompilieren von der hauptanwendung die IPlugin.dll neu kompiliert wird... Jetzt mal ne sau blöde frage... Wie stelle ich das ab?

Alle 3 Projekte in eine Projektmappe legen und erstellen. Wenn du sicher gehen willst, kannst du auch alles neu Erstellen verwenden. Musst halt nur dafür sorgen, dass nach dem Erstellen die einzelnen Projektausgaben an der richtigen Stelle liegen. Den Ausgabepfad kannst du in den jeweiligen Projekteigenschaften individuell festlegen.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

V
ViperNeo Themenstarter:in
352 Beiträge seit 2008
vor 13 Jahren

ich hab jetzt in den Release einstellungen festgelegt das nur die Hauptanwendung kompiliert wird. Außerdem hab ich die Verweise nicht als Projektverweis sondern als Direktverweis auf das Kompilat des Plugins hinterlegt. Jetzt wird das Plugin nicht mehr kompiliert bei jedem Kompiliervorgang und es funktioniert.... Meine güte war das eine schwere Geburt. Vielen Dank!