Laden...

Problem mit Reflections

Erstellt von core vor 15 Jahren Letzter Beitrag vor 15 Jahren 2.479 Views
C
core Themenstarter:in
157 Beiträge seit 2008
vor 15 Jahren
Problem mit Reflections

Hi@all,

ich lade eine externe Library dynamisch mit Hilfe von Reflections in meine Applikation.


private void initialize(byte[] rawAssembly)
{
     Assembly assembly = Assembly.Load(rawAssembly);
     string toolConnector = typeof(ICoreToolConnector).ToString().Substring(typeof(ICoreToolConnector).ToString().LastIndexOf(".") + 1);
     foreach (Type type in assembly.GetExportedTypes())
     {
          if (type.GetInterface(toolConnector) != null)
          {
               ICoreToolConnector iCoreToolConnector = (ICoreToolConnector)Activator.CreateInstance(type);
               this.coreTool = iCoreToolConnector.initialize(this);
               break;
          }
     }
}

Das klappt beim ersten mal auch ohne Probleme, aber wenn ich es ein zweites Mal laden will, wirft die Zeile "ICoreToolConnector iCoreToolConnector = (ICoreToolConnector)Activator.CreateInstance(type);" eine System.Reflections.TargetInvocationException, weil die Resource, sprich die Library, nicht mehr gefunden werden kann. Was ist da jetzt los? 🤔

Hat einer von Euch ne Idee, wie das Problem zu lösen ist?

core

1.665 Beiträge seit 2006
vor 15 Jahren

Hast du schon GetTypes() anstatt GetExportedTypes() probiert?

Erklär mir mal diese mysteriöse Codezeile:

string toolConnector = typeof(ICoreToolConnector).ToString().Substring(typeof(ICoreToolConnector).ToString().LastIndexOf(".") + 1);

was soll da im Optimalfall zurückkommen?

C
core Themenstarter:in
157 Beiträge seit 2008
vor 15 Jahren

Hi JunkyXL,

"typeof(ICoreToolConnector).ToString()" gibt den kompletten Namen des Interfaces inkusive Namespace wieder. In meinem Fall waere das dann "Core.Tools.IToolConnector". da ich nur den Namen des Interfaces, sprich "ICoreToolConnector" beim Vergleich "if (type.GetInterface(toolConnector) != null)" brauche, hole ich mir den Substring. Sicherlich koennte ich an dieser Stelle auch "string toolConnector = "ICoreToolConnector";" schreiben, aber ich denke, dass das auch nicht die Ursache fuer mein Problem ist.

core

1.665 Beiträge seit 2006
vor 15 Jahren
C
core Themenstarter:in
157 Beiträge seit 2008
vor 15 Jahren

Hi JunkyXL,

danke fuer den Tip. Damit kann ich an dieser Stelle den Code etwas optimieren, aber mein Problem wird es sicherlich nicht loesen. Ich werde aber nacher noch mal deinen Tip

Hast du schon GetTypes() anstatt GetExportedTypes() probiert?

ausprobieren. Ich denke nicht, dass damit das Problem mit der System.Reflections.TargetInvocationException geloest sein wird, lass mich aber gern positiv ueberrachen.

Ich werde Euch auf jedenfall schreib. Egal obs geklappt hat oder nicht.

core

5.742 Beiträge seit 2007
vor 15 Jahren

Hallo core,

musst du wirklich die Überladung Assembly.Load(byte[]) verwenden?

Verwende lieber Assembly.LoadFile(string) (sofern möglich).

Ich hoffe, das ist wirklich die Methode, von der ich denke, dass sie es ist. Die Assembly.LoadXXX Methoden bringe ich immer durcheinander.

C
core Themenstarter:in
157 Beiträge seit 2008
vor 15 Jahren

Hi winSharp93,

warum? Wo liegt der Vorteil von Assembly.LoadFile(string)? ?(

core

5.742 Beiträge seit 2007
vor 15 Jahren

warum? Wo liegt der Vorteil von Assembly.LoadFile(string)?

Besser noch ist Assembly.Load(string) (was aber auf dasselbe wie LoadFile herausläuft, wenn man einen direkten Pfad angibt).

Da ich mir nicht 100%ig sicher bin, will ich auch nicht versuchen, das hier zu erklären.
Aus eigener Erfahrung kann ich jedenfalls sagen, dass ansonsten teilweise dieselbe Assembly mehrfach geladen wird und Typen, die eigentlich "gleich" sein sollten, das plötzlich nicht mehr sind.

Probiere einfach mal eine andere Variante aus - vielleicht funktioniert es dann ja.

C
core Themenstarter:in
157 Beiträge seit 2008
vor 15 Jahren

Ok,

dann werde ich das mal austesten. Ich werde Euch dann berichten, wie es ausgegangen ist.

Danke!

core

C
core Themenstarter:in
157 Beiträge seit 2008
vor 15 Jahren

Hallo da bin ich wieder,

bevor ich den von winSharp93 vorgeschlagenen Weg gehen werde, habe erst einmal versucht, die Ursache für mein aktuelles Problem einzugrenzen. Fakt ist: Ich kann eine Assemby über Refelection nur genau ein mal laden. Beim zweiten Mal wirft mir der Contruktor der Klassen des Assemblys auf den ich zugreife eine Exception. Er könne auf einmal das zum C#-File gehörende XAML-File nicht mehr finden? 🤔

Das versehe ich aber nicht. Er hat es doch beim ersten mal ohne Probleme geschafft? Hier komme ich also beim meinem Ansatz nicht mehr weiter. X(

Weis einer von Euch was da los ist?

C
core Themenstarter:in
157 Beiträge seit 2008
vor 15 Jahren

Hi Leute,

nun zum meinem Veruch, winSharp93 sein Vorschlag umzusetzen. Dieser scheitet beirets beim erstem mal laden des Assemblys mit einer IOException. Der von mir angegebenen Pfad würde nicht stimmen. In der MessageBox sind die Slash-Zeichen des mir als falsch vorgeworfenen Pfades wirklich komisch. Ich übergeben den Pfad aber meiner Meinung nach vollkommen richtig.


string toolPath = @"http://localhost/CORE/Application Files/Tools/TextEdit.ctl";

Was ist denn hier nun los? Langsam verzweifle ich . X(

core

5.742 Beiträge seit 2007
vor 15 Jahren
  
string toolPath = @"http://localhost/CORE/Application Files/Tools/TextEdit.ctl";  
  

Verwendest du Silverlight?
Wenn nicht, würde ich es testweise einmal mit einem "konventionellen" Pfad versuchen. (also in der Art "C:\Programme\MyApplication\Test.dll").

Was genau ist denn eine .ctl Datei?
Soweit ich weiß nichts .NET spezifisches, oder?
Wenn du sie umbenannt hast, versuche einmal, was passiert, wenn du sie nicht umbenennst.

Andere Frage:
Warum musst du dieselbe Assembly mehrfach in die selbe AppDomain laden. Für mich macht das keinen Sinn 🤔

C
core Themenstarter:in
157 Beiträge seit 2008
vor 15 Jahren

Hi winSharp93,

nein ich verwende kein Silverlight. Es ist eine WPF-Browser-Applikation mit vollem .NET-Funktionsumfang.

Was genau ist denn eine .ctl Datei? Soweit ich weiß nichts .NET spezifisches, oder?
Wenn du sie umbenannt hast, versuche einmal, was passiert, wenn du sie nicht umbenennst.

Ja Du hast recht. Es ist normalerweise eine *.dll, die ich umbenennen musste, weil es sonst nicht ging. Wenn ich eine *.dll-Datei versucht habe vom IIS zu laden, gab er mir immer eine Exception (500) zurück. Ich hatte diesbezüglich auch eine Frage ins Forum gestellt. Leider konnte mir keiner helfen und so habe ich sie erst einmal umbenannt, was aber nach meiner Planung nicht so bleiben soll. Ist nur eine mittelfristige Notlösung.
(ctl steht übrigens für Core-Tool-Library)

Warum musst du dieselbe Assembly mehrfach in die selbe AppDomain laden. Für mich macht das keinen Sinn

Meine Applikation soll einmal ein WebDesktop werden. In diesem können dann die Tools (*.ctl-files) wie Programme auf dem WindowsDesktop geladen und angezeigt werden. Manche Programme wie z.B. einen Text-Editor will man aber möglicherweise mehrmals öffnen können. Daher der Versuch dieselbe Assembly mehrmals zu laden.

Vieleicht kennst Du ja einen bessere und vorallem funktionierende Lösung bzw. einen anderen Ansatz, mit dem ich das erreichen könnte? Die Tools sollen auf jeden Fall nur nach Bedarf vom Server nachgeladen werden und nicht alle auf einmal mit dem WebDesktop zusammen. Desweiteren sollen einige Tools natürlich bei Bedarf mehrfall geöffnet werden können.

Ich hab Dir mal einen Screenshot angehängt, damit Du dir ein Bild von dem machen kannst, was ich will.

core

5.742 Beiträge seit 2007
vor 15 Jahren

Meine Applikation soll einmal ein WebDesktop werden. In diesem können dann die Tools (*.ctl-files) wie Programme auf dem WindowsDesktop geladen und angezeigt werden. Manche Programme wie z.B. einen Text-Editor will man aber möglicherweise mehrmals öffnen können.

Verwende dann am besten mehrere _AppDomain_s (für jede offene Anwendung eine).
Dann stürzt dir bei einer unbehandelten Exception (normalerweise) auch nur die jeweilige "Anwendung" ab und nicht dein ganzer WebDesktop.

Die Tools sollen auf jeden Fall nur nach Bedarf vom Server nachgeladen werden und nicht alle auf einmal mit dem WebDesktop zusammen.

Soweit ich weiß passiert das automatisch. DLLs werden erst geladen, wenn sie tatsächlich gebraucht werden.

C
core Themenstarter:in
157 Beiträge seit 2008
vor 15 Jahren

Hi winSharp93,

Verwende dann am besten mehrere AppDomains (für jede offene Anwendung eine).
Dann stürzt dir bei einer unbehandelten Exception (normalerweise) auch nur die jeweilige "Anwendung" ab und nicht dein ganzer WebDesktop.

Diesen Ansatz hatte ich vorher schon einmal ausprobiert. Problematisch wurde es allerdings mit den EventHandlern des WebDesktops die nicht fehlerfrei in den Frames, in denen die Tools ausgeführt wurden, funktionierten. Zum anderen hatte ich dann auch Probleme mit den Ebenen. Die in den Frames geladen Tool-Applikation war immer im Vordergrund und ließ sich auch nicht mehr mit den Fenstern nach hinten setzen. Deshalb habe ich ja versucht, die Tools über Reflections in den WebDesktop zu laden, was bis auf die Exception beim mehrfachen laden einwandfrei läuft und die eben beschreibenen Fehler eliminiert.

Soweit ich weiß passiert das automatisch. DLLs werden erst geladen, wenn sie tatsächlich gebraucht werden.

Nun ja, das ist schon so. Aber ich möchte nicht, dass der Client alle Tools komplett mit dem WebDesktop zusammen herunterladet. Die Tools sollen erst dann geladen werden, wenn sie auch genutzt werden. Des weiteren möchte ich später noch ein Rechtemanagement für die Nutzung der einzelnen Tools integrieren. Ein Tool dann z.B. vom Server runter zu laden, obwohl man kein Recht zu dessen Ausführung hat macht spätestens dann keinen Sinn mehr.