Laden...

Assembly inkl Referenzen dynamisch laden

Erstellt von Golo Roden vor 15 Jahren Letzter Beitrag vor 8 Jahren 3.942 Views
Golo Roden Themenstarter:in
4.207 Beiträge seit 2003
vor 15 Jahren
Assembly inkl Referenzen dynamisch laden

Hallo,

folgendes Szenario: Ich möchte eine Assembly dynamisch zur Laufzeit laden, muss dabei aber auch gegebenenfalls referenzierte Assemblies laden, und eventuell wieder von diesen referenzierte, usw ...

Ich habe folgene Lösung im Kopf:

Eigentliche Assembly als ReflectionOnly laden, und mit GetReferencedAssemblies ermitteln, welche Assemblies referenziert werden. Diese auch wieder als ReflectionOnly laden usw ... anschließend den so entstandenen Baum rückwärts wieder durchlaufen und die Assemblies "richtig" laden, also mit Load / LoadFrom.

Dürfte funktionieren, kommt mir aber SEHR umständlich vor.

Geht das irgendwie auch einfacher?

Viele Grüße,

Golo

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

1.130 Beiträge seit 2007
vor 15 Jahren

Warum ned direkt (als baum) laden?

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Golo Roden Themenstarter:in
4.207 Beiträge seit 2003
vor 15 Jahren

Weil ich die Assembly ja schon geladen haben muss, bevor ich ein GetReferencedAssemblies machen kann. Und das geht nur per ReflectionOnly - sonst geht das Laden schief, weil die abhängigen Assemblies halt nicht da sind.

Als Alternative bin ich noch auf das AssemblyResolve-Event gestoßen - kann mir dazu jemand aus Erfahrung ein bisschen was sagen? Vor- / Nachteile?

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

Golo Roden Themenstarter:in
4.207 Beiträge seit 2003
vor 15 Jahren

So, mit AssemblyResolve ließ sich das ganze sehr schön und elegant lösen.

Einziges Problem: Ein Assembly.GetTypes auf die dynamisch geladenen Assemblies schlägt fehl - wiederum kann angeblich eine Assembly nciht gefunden werden, obwohl dieses Mal kein AssemblyResolve ausgelöst wird.

Hat jemand eine Idee, woran das liegen könnte?

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

Golo Roden Themenstarter:in
4.207 Beiträge seit 2003
vor 15 Jahren

Hat sich erledigt - es lag an einer nicht passenden Versionsnummer im Strongname einer referenzierten Assembly.

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

S
142 Beiträge seit 2007
vor 15 Jahren

Hallo Golo,

Könntest Du ein paar Details dazu schreiben wie Du das Problem mit dem AssemblyResolve Event lösen konntest? Habe das Gleiche vor, bin aber noch nicht ganz dahinter gekommen...

thx 😃 Steav

Golo Roden Themenstarter:in
4.207 Beiträge seit 2003
vor 15 Jahren

Ich habe mich an das AssemblyResolve-Event von AppDomain.CurrentDomain angehängt.

Der Eventhandler bekommt als eventArgs.Name den Namen der nicht gefundenen Assembly mit.

Letztlich prüfe ich dort dann mit File.Exists, ob die Assembly im angegeben Ordner existiert - wenn ja, wird sie mit LoadFrom geladen - ansonsten wird sie mit Load versucht, aus dem GAC oder sonstwo (mit Probing) herzuholen.

Wenn eins von beidem klappt, gebe ich die Assembly entsprechend zurück. Wenn beides erfolglos bleibt, fliegt eine Exception.

Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden

www.goloroden.de
www.des-eisbaeren-blog.de

S
142 Beiträge seit 2007
vor 15 Jahren

Ich hab merkwürdigerweise bereits ein problem mich an das Event dranzuhängen....
Ich versuche es vor dem .Load zuzuweisen und setze dort einen Breakpoint, der Code kommt aber nie dort an sondern das Programm stürzt bereits vor dem Erreichen des Events ab:

Die Datei oder Assembly "TrackBox, 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.

Überseh ich hier etwas Offensichtliches?


        private void btn_LadeInNeuerAppDomain_Click(object sender, EventArgs e)
        {
            AppDomain NeueDomain = AppDomain.CreateDomain("TestDomainXYZ");

            NeueDomain.AssemblyResolve += new ResolveEventHandler(NeueDomain_AssemblyResolve);
            NeueDomain.Load(System.IO.File.ReadAllBytes(openFileDialog1.FileName));
        }

        System.Reflection.Assembly NeueDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            // Hier kommt er nie an
            MessageBox.Show("success");
            return null;
        }

Mit einem Try / Catch um das Load gehts auch nicht....

hab mal die gesamte Exception geprüft:

System.IO.FileNotFoundException: Die Datei oder Assembly "TrackBox, 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.

Dateiname: "TrackBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"

bei System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)

bei System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)

bei System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)

bei System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)

bei System.Reflection.Assembly.Load(String assemblyString)

bei System.UnitySerializationHolder.GetRealObject(StreamingContext context)

bei System.AppDomain.Load(Byte[] rawAssembly)

bei Allgemeine_Testsolution.Form1.btn_LadeInNeuerAppDomain_Click(Object sender, EventArgs e) in D:\Steav\Visual Studio 2008\Projects\Allgemeine Testsolution\Allgemeine Testsolution\Form1.cs:Zeile 63.

=== Zustandsinformationen vor Bindung ===

LOG: Benutzer = SW\sboecking

LOG: DisplayName = TrackBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
(Fully-specified)

LOG: Appbase = file:///D:/Steav/Visual Studio 2008/Projects/Allgemeine Testsolution/Allgemeine Testsolution/bin/Debug/

LOG: Ursprünglicher PrivatePath = NULL

Aufruf von Assembly : (Unknown).

===

LOG: Diese Bindung startet im default-Load-Kontext.

LOG: Es wurde keine Anwendungskonfigurationsdatei gefunden.

LOG: Die Computerkonfigurationsdatei von C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config wird verwendet.

LOG: Die Richtlinie wird derzeit nicht auf den Verweis angewendet (private, benutzerdefinierte, teilweise oder pfadbasierte Assemblybindung)

LOG: Download von neuem URL file:///D:/Steav/Visual Studio 2008/Projects/Allgemeine Testsolution/Allgemeine Testsolution/bin/Debug/TrackBox.DLL.

LOG: Download von neuem URL file:///D:/Steav/Visual Studio 2008/Projects/Allgemeine Testsolution/Allgemeine Testsolution/bin/Debug/TrackBox/TrackBox.DLL.

LOG: Download von neuem URL file:///D:/Steav/Visual Studio 2008/Projects/Allgemeine Testsolution/Allgemeine Testsolution/bin/Debug/TrackBox.EXE.

LOG: Download von neuem URL file:///D:/Steav/Visual Studio 2008/Projects/Allgemeine Testsolution/Allgemeine Testsolution/bin/Debug/TrackBox/TrackBox.EXE.

3.971 Beiträge seit 2006
vor 15 Jahren

Letztlich prüfe ich dort dann mit File.Exists, ob die Assembly im angegeben Ordner existiert - wenn ja, wird sie mit LoadFrom geladen - ansonsten wird sie mit Load versucht, aus dem GAC oder sonstwo (mit Probing) herzuholen.

Im GAC, Programmverzeichnis, Probing (in der Reihenfolge) sucht die CLR bereits selbst nach (dynamisch) angeforderten Assemblies. Das Programmverzeichnis und ausgehend davon das Probing geschieht über den Wert aus AppDomainSetup.ApplicationBase-Eigenschaft (Standard ist das Verzeichnis der ausgeführten Exe).

Das ganze funktioniert allerdings nur, wenn man bei CreateInstance einen vollqualifizierenden Typnamen angibt.

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

M
12 Beiträge seit 2012
vor 8 Jahren

hallo zusammen...

habe zwar gesehen das der post schon etwas älter ist, aber vlt haut es ja trotzdem hin 😃

ich habe ziemlich das gleiche vor wie der Golo hier bei eröffnung des eintrags, mein denkansatz ging auch in die richtung..

wie hast du bzw habt ihr das letztendlich umgesetzt?

bin für jeden tip dankbar

Danke und Gruß 😃

16.842 Beiträge seit 2008
vor 8 Jahren

Überleg Dir, ob Du das wirklich heute noch willst. Das Vorgehen hier ist schließlich schon einige Jahre alt.
Im neuen .NET Core wirst Du das auf diese Weise nicht mehr machen können, da es keine AppDomain mehr geben wird.
Wenn ihr also vor habt .NET Core irgendwann einzusetzen, dann überlegt euch das fünf mal.

M
12 Beiträge seit 2012
vor 8 Jahren

hab vielen dank für deine prommte und ehrliche antwort.. 😃

hab mich noch bisschen umgeschaut wie ich es noch lösen könnte und bin nun bei MEF hängen geblieben.

habe hier auch ein recht gescheites tut dazu gefunden

ich denke damit kann ich das sinnvoller und gescheiter umsetzen, auch wenn der "umbau" ein wenig zeit in anspruch nimmt.

danke dir nochmals

Gruß
Mandriva