Laden...

[erledigt] Eingriff in Type.GetType zum Auflösen der korrekten Assembly

Erstellt von Dust Signs vor 11 Jahren Letzter Beitrag vor 11 Jahren 3.936 Views
D
Dust Signs Themenstarter:in
95 Beiträge seit 2006
vor 11 Jahren
[erledigt] Eingriff in Type.GetType zum Auflösen der korrekten Assembly

Hallo!

Ich habe mehrere Typen, nennen wir einen davon einmal T, deren Namen als typeof(T).FullName (um später wieder die Assembly, aus der sie stammen, rekonstruieren zu können - Name alleine reicht hier nicht) gespeichert werden. Via Type.GetType kann ich dann später Informationen über den gespeicherten Typnamen bekommen, Instanzen erzeugen etc. So weit, so gut, wenn sich Assemblyname und -version nicht ändern.
Ändert sich die Version der Assembly, schlägt das Auflösen des Namens zu einem Typ fehl. Wie ich herausgefunden habe, kann ich hier Abhilfe schaffen, falls es ein Typ ist, dessen dazugehörige Assembly ich schon zur Compilezeit kenne (kommt in meinem Anwendungsfall glücklicherweise oft vor, wenn Abhängigkeiten bereits geladen sind), indem ich auf das AssemblyRevolve-Ereignis der aktuellen AppDomain reagiere:

            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(delegate(object obj, ResolveEventArgs args) //React on assembly resolving errors on changing library versions
            {
                return Assembly.GetAssembly(typeof(EinTypTDerBekanntIst)); //Try the library's current assembly (version)
            });

Das klappt soweit. Mein aktuelles Problem: wenn ich meine Libraries und mein Hauptprogramm mit ILMerge zusammenfüge und mit der zusammengefügten Assembly z.B. den Typ MergedAssembly.T (als String) speichere, liefert Type.GetType beim Starten der Anwendung alleine (d.h. mit externen Libraries) zwar ohne Exception einen Typ, doch verweist dieser "ins Nichts", d.h. er hat nicht die richtigen Attribute, implementiert keine Schnittstellen etc. Gibt es irgendeine Möglichkeit, in Type.GetType über ein anderes Ereignis oder eine Einstellung so einzugreifen, dass ich der Runtime dazu bewegen kann, die aus meiner Sicht korrekte, d.h. aktuelle, Assembly aus meinen Abhängigkeiten zu verwenden, ohne dass der Assemblyname dabei gleich wie die im String sein muss?

Danke im Voraus für eure Hilfe
Grüße
Dust Signs

Die Nummer, die Sie gewählt haben, ist imaginär. Bitte drehen Sie Ihr Telefon um 90° und versuchen Sie es erneut.

B
387 Beiträge seit 2005
vor 11 Jahren

Hi,

zuerst mal muss ich sagen Hää...?
Ich versteh dein Problem ehrlich gesagt nicht so ganz, versuche aber trotzdem mal eine Antwort zu geben.

Ich frage mich gerade, wass das AssemblyResolve bei dir überhaupt für einen Sinn macht. Das Ereignis wird aufgerufen, wenn eine Assembly zu einem Typ nicht gefunden werden kann und bietet die möglichkeit, sie etwa aus einem anderen Pfad o. Ä. zu laden. Bei dir würde eigentlich dieses typeof(EinTypTDerBekanntIst) bereits das Laden der Assembly auslösen, und zwar der Assembly, in der EinTypTDerBekanntIst enthalten ist. Sollte das eine andere sein und du gaukelst der CLR vor, dass das die eigentlich gesuchte Assembly ist, und du kriegst Probleme später im Programm. Ich würde die Assembly nicht per Assembly.GetAssembly(typeof(...)) zurückgeben, sondern innerhalb des Ereignisses einfach die richtige Assembly laden (z. B. aus einer Datei per Assembly.LoadFile Methode).

Gruß
Roland

D
Dust Signs Themenstarter:in
95 Beiträge seit 2006
vor 11 Jahren

Hallo!

Vielleicht habe ich mich zu kompliziert ausgedrückt. Ich gebe mal ein konkretes Beispiel: Die mit ILMerge zu M zusammengefügten Assemblies A (Anwendung) und L (Library) werden gestartet und ein Typname, Namespace.Test, als String gespeichert, d.h. z.B.

Namespace.Test, M, Version=1.0.4467.38266, Culture=neutral, PublicKeyToken=null

Versuche ich nun, die Anwendung alleine zu starten, den String zu lesen und in einen Typ umzuwandeln (der sich in L befindet und zur Laufzeit geladen ist), wird nicht der richtige Typ gefunden. Selbst wenn ich den Loader zwinge, L zu verwenden, gibt er mir nicht den richtigen Typ zurück - warum, weiß ich nicht. Ich nehme an, dass es daran liegt, dass er obigen Typ sucht, aber den hier findet:

Namespace.Test, L, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Grüße
Dust Signs

Die Nummer, die Sie gewählt haben, ist imaginär. Bitte drehen Sie Ihr Telefon um 90° und versuchen Sie es erneut.

49.485 Beiträge seit 2005
vor 11 Jahren

Hallo Dust Signs,

wenn ich dich richtig verstehe, würde es dein Problem lösen, wenn du ohne ILMerge arbeitest. Da das ohnehin das übliche Vorgehen ist, würde ich dir dazu raten.

Oder mit anderen Worten, dein Problem tritt nur auf, weil du dir das Leben mit dem ILMerge selbst unnötig schwer machst.

herbivore

2.187 Beiträge seit 2005
vor 11 Jahren

Hallo Dust Sings,

Das Thema gab es schon ein paar mal im Forum.
[erledigt] AssemblyResolve - einbinden dlls in die exe
Benutzer Programm generieren lassen
Entwurf eines eigenen Frameworks
...
(suche nach "netz dll")

Es gibt auch eine fertige Softwar die das kann (selber nie ausprobiert):
.Netz

Gruß
Juy Juka

D
Dust Signs Themenstarter:in
95 Beiträge seit 2006
vor 11 Jahren

Danke für den Hinweis mit .NETZ. Ich werde das mal an Stelle von ILMerge versuchen.

Grüße
Dust Signs

Die Nummer, die Sie gewählt haben, ist imaginär. Bitte drehen Sie Ihr Telefon um 90° und versuchen Sie es erneut.

D
Dust Signs Themenstarter:in
95 Beiträge seit 2006
vor 11 Jahren

Hallo!

Ich habe .NETZ ausprobiert - danke für euren Hinweis. Es löst das Problem prinzipiell, schafft aber auch ein neues - die Berücksichtigung unterschiedlicher Versionen über das AssemblyResolve-Event funktioniert nun nicht mehr. Nach einigen Stunden des Debuggens habe ich herausgefunden, dass das AssemblyResolve-Event in den .NETZ-Executables gar nicht mehr aufgerufen wird. Damit ist die "Lösung" für mich keine wirkliche, da ich das Problem mit den unterschiedlichen Assembly-Versionen, das ich schon gelöst hatte, nun nicht mehr lösen kann. Oder gibt es irgendeinen Workaround dazu?

EDIT: Ich habe die Lösung gefunden: Die .NETZ-Executable listet manche Assemblies in AppDomain.CurrentDomain.GetAssemblies() doppelt. Sucht man anhand des Assembly-Namen die Assembly manuell in der o.g. Liste, wählt den zweiten Treffer (nicht den ersten), kann man mittels GefundeneAssembly.GetType(...) den richtigen Typ bekommen.

Grüße
Dust Signs

Die Nummer, die Sie gewählt haben, ist imaginär. Bitte drehen Sie Ihr Telefon um 90° und versuchen Sie es erneut.

B
387 Beiträge seit 2005
vor 11 Jahren

Hi,

...Die .NETZ-Executable listet manche Assemblies in AppDomain.CurrentDomain.GetAssemblies() doppelt...

Ich würde dann aber mal genau überprüfen, ob im Programm noch alles so funktioniert, wie es soll. Glaub nicht, dass es ohne Folgen bleibt, wenn Assemblies doppelt geladen werden.

Gruß
Roland

D
Dust Signs Themenstarter:in
95 Beiträge seit 2006
vor 11 Jahren

Hallo Roland!

Das Programm scheint soweit noch einwandfrei zu funktionieren. Soweit ich erkennen kann, ist momentan nur die "Haupt"-, d.h. Einsprungs-Assembly doppelt gelistet - einmal ohne Pfad mit dem den eigentlichen Klassen etc., und einmal mit Pfad und mit nur einer NETZ_0_4_8-Klasse (die wahrscheinlich für die Dekomprimierung und das Laden zuständig ist). Das scheint sonst nichts weiter zu beeinträchtigen.

Grüße
Dust Signs

Die Nummer, die Sie gewählt haben, ist imaginär. Bitte drehen Sie Ihr Telefon um 90° und versuchen Sie es erneut.

6.911 Beiträge seit 2009
vor 11 Jahren

Hallo Dust Signs,

wählt den zweiten Treffer

wenn das nicht explizit so dokumentiert ist, so würde ich mich darauf nicht verlassen. Es kann zum einen nicht deterministisch sein, also die Reihenfolge willkürlich, und zum anderen könnte sich bei einem Update von NETZ diese Reihenfolge auch ändern.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

D
Dust Signs Themenstarter:in
95 Beiträge seit 2006
vor 11 Jahren

Das mag sein, aber momentan ist das die einzige Lösung, die zuverlässig funktioniert. Mir wäre es auch lieber, wenn ich die Assembly-Auflösung nicht händisch und unter Zuhilfenahme dieser Beobachtungen bzgl. der Reihenfolge machen müsste, aber anders funktioniert es leider nicht.
Falls jemand Alternativen kennt, bitte immer her damit 😃

Dust Signs

Die Nummer, die Sie gewählt haben, ist imaginär. Bitte drehen Sie Ihr Telefon um 90° und versuchen Sie es erneut.

F
10.010 Beiträge seit 2004
vor 11 Jahren

Klar gibt es alternativen, aber die ( z.b. von herbivore ignorierte ) willst du nicht hören.

  1. Warum gibt es einen String der eine andere Versionsnummer hat als die Assmbly?
  2. Solltest Du mal das Prinzip dahinter verstanden haben, wäre doch eine Abfrage ohne Version zielführend.
  3. Warum machst du diesen .. Überhaupt?
D
Dust Signs Themenstarter:in
95 Beiträge seit 2006
vor 11 Jahren

Die Versionsnummer kodiert in meinem Anwendungsfall das Builddatum und wird daher zur Speicherung dieser Information verwendet. Die Struktur der Typen ändert sich über die Versionen hinweg nicht, weswegen ich die Version nicht überprüfen muss.
Zudem verstehe ich nicht, was du mit

aber die ( z.b. von herbivore ignorierte ) willst du nicht hören meinst: Ich habe ILMerge durch .NETZ ersetzt und bin nun dadurch auf andere Workarounds angewiesen, die ich oben beschrieben habe.

Dust Signs

Die Nummer, die Sie gewählt haben, ist imaginär. Bitte drehen Sie Ihr Telefon um 90° und versuchen Sie es erneut.

F
10.010 Beiträge seit 2004
vor 11 Jahren

Nein, warum machst du das überhaupt.

  1. Warum ILMerge oder Netz?
  2. Warum benutzt du überhaupt die Versionsnummer, wenn die ( deinen Angaben nach ) doch sowieso obsolet ist?
D
Dust Signs Themenstarter:in
95 Beiträge seit 2006
vor 11 Jahren

Nein, warum machst du das überhaupt.

Hauptsächlich benötige ich diese Information für einen eigenen Serializer, mit dem ich einige spezielle Anforderungen erfüllen muss, die mir weder die im Framework eingebauten noch die sonst verfügbaren Serializer erfüllen können.

  1. Warum ILMerge oder Netz?

Am Schluss muss eine Assembly herauskommen. Diese Einschränkung stammt nicht von mir, sondern ist von außen vorgegeben.

  1. Warum benutzt du überhaupt die Versionsnummer, wenn die ( deinen Angaben nach ) doch sowieso obsolet ist?

Auch das ist von außer vorgegeben.

Dust Signs

Die Nummer, die Sie gewählt haben, ist imaginär. Bitte drehen Sie Ihr Telefon um 90° und versuchen Sie es erneut.