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
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
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
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
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
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
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.
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...
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ß 😃
Ü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.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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