Ich habe AppDomain
mit einem anderen Basisverzeichnis erstellt. Ich kann jedoch scheinbar nicht die aktuell ausführende Assembly in die andere Anwendungsdomäne laden, ohne eine Kopie der aktuell ausgeführten Assembly im Basisverzeichnis zu haben. Ich habe sogar versucht, es aus den Bytes zu laden.
Ich bekomme keine Ausnahme, wenn ich versuche zu laden, aber wenn ich versuche zu verwenden:
%Vor%Ich bekomme:
Datei oder Assembly konnte nicht geladen werden ........... Das System kann die angegebene Datei nicht finden.
Mein Code ist wie folgt:
%Vor%Aktualisierung:
Es scheint, dass die Assembly geladen wird, wenn ich in der Ausgabe nachschaue, sehe ich das
'TaskExecuter.Terminal.vshost.exe' (Verwaltet (v4.0.30319)): Loaded 'NLog' 'TaskExecuter.Terminal.vshost.exe' (Managed (v4.0.30319)): Loaded 'TaskExecuter', Symbole geladen.
aber ich bekomme immer noch die Ausnahme ... ich verstehe das nicht
System.IO.FileNotFoundException wurde nicht behandelt Nachricht = Konnte nicht geladen werden Datei oder Assembly 'TaskExecuter, Version = 1.0.4244.31921, Culture = neutral, PublicKeyToken = null 'oder eine seiner Abhängigkeiten. Das System kann die angegebene Datei nicht finden. Quelle = mscorlib
FileName = TaskExecuter, Version = 1.0.4244.31921, Kultur = neutral, PublicKeyToken = null FusionLog ==== Informationen zum Status der Vorbindung === LOG: Benutzer = Peter-PC \ Peter LOG: DisplayName = TaskExecuter, Version = 1.0.4244.31921, Kultur = neutral, PublicKeyToken = null (Vollständig angegeben) LOG: Appbase = Datei: /// C: / ProgramData / TaskExecuter / TaskLib / uTorrentTasks LOG: Initial PrivatePath = C: \ Programme \ TaskExecuter \ TaskLib \ uTorrentTasks \ Libs Aufruf der Baugruppe: (Unbekannt). === LOG: Diese Bindung beginnt im Standard-Ladekontext. LOG: Verwenden Anwendungskonfigurationsdatei: d: \ users \ peter \ documents \ visual studio 2010 \ Projekte \ TaskExecuter \ TaskExecuter.Terminal \ bin \ Release \ TaskExecuter.Terminal.vshost.exe.Config LOG: Verwenden der Hostkonfigurationsdatei: LOG: Verwenden der Maschinenkonfiguration Datei von C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ config \ machine.config. LOG: Richtlinie wird derzeit nicht auf Referenz angewendet (privat, benutzerdefinierte, partielle oder standortbasierte Assembly-Bindung). LOG: Versuch Download der neuen URL file: /// C: /ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter.DLL. LOG: Versuch, die neue URL herunterzuladen file: /// C: /ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter/TaskExecuter.DLL. LOG: Versuch, die neue URL herunterzuladen file: /// C: /ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter.DLL. LOG: Versuch, die neue URL herunterzuladen file: /// C: /ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter/TaskExecuter.DLL. LOG: Versuch, die neue URL herunterzuladen file: /// C: /ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter.EXE. LOG: Versuch, die neue URL herunterzuladen file: /// C: /ProgramData/TaskExecuter/TaskLib/uTorrentTasks/TaskExecuter/TaskExecuter.EXE. LOG: Versuch, die neue URL herunterzuladen file: /// C: /ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter.EXE. LOG: Versuch, die neue URL herunterzuladen file: /// C: /ProgramData/TaskExecuter/TaskLib/uTorrentTasks/Libs/TaskExecuter/TaskExecuter.EXE.StackTrace: bei System.Reflection.RuntimeAssembly._nLoad (AssemblyName Dateiname, Zeichenfolge codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark & amp; stackMark, Boolean throwOnFileNotFound, Boolean forInspection, Boolean suppressSecurityChecks) bei System.Reflection.RuntimeAssembly.nLoad (AssemblyName Dateiname, Zeichenfolge codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark & amp; stackMark, Boolean throwOnFileNotFound, Boolean forInspection, Boolean suppressSecurityChecks) beim System.Reflection.RuntimeAssembly.InternalLoadAssemblyName (Assemblyname assemblyRef, Evidence assemblySecurity, StackCrawlMark & amp; Stapelmark, Boolean forInspection, Boolean suppressSecurityChecks) bei System.Reflection.RuntimeAssembly.InternalLoad (String assemblyString, evidence assemblySecurity, StackCrawlMark & amp; Stapelmark, Boolean für Introspektion) bei System.Reflection.Assembly.Load (String assemblyString) beim System.Runtime.Serialization.FormatterServices.LoadAssemblyFromString (String AssemblyName) beim System.Reflection.MemberInfoSerializationHolder.ctor (SerializationInfo info, StreamingContext Kontext) bei System.AppDomain.DoCallBack (CrossAppDomainDelegate callBackDelegate) in TaskExecuter.AppDomainHelper.CreateAppDomain (String dir, String-Name) in d: \ Benutzer \ Peter \ Dokumente \ Visual Studio 2010 \ Projekte \ TaskExecuter \ TaskExecuter \ AppDomainHelper.cs: Zeile 50 bei TaskExecuter.TaskManagment.TaskFinder.Probe () in d: \ Benutzer \ Peter \ Dokumente \ Visual Studio 2010 \ Projekte \ TaskExecuter \ TaskExecuter \ TaskManagement \ TaskFinder.cs: Zeile 29 bei TaskExecuter.TaskManagment.TaskManager.LoadTasks () in d: \ Benutzer \ Peter \ Dokumente \ Visual Studio 2010 \ Projekte \ TaskExecuter \ TaskExecuter \ TaskManagment \ TaskManager.cs: Zeile 63 bei TaskExecuter.TaskManagment.TaskManager.Start () in d: \ Benutzer \ Peter \ Dokumente \ Visual Studio 2010 \ Projekte \ TaskExecuter \ TaskExecuter \ TaskManagment \ TaskManager.cs: Zeile 95 bei TaskExecuter.Terminal.Program.Main (String [] args) in d: \ Benutzer \ Peter \ Dokumente \ Visual Studio 2010 \ Projekte \ TaskExecuter \ TaskExecuter.Terminal \ Program.cs: Zeile 16 bei System.AppDomain._nExecuteAssembly (RuntimeAssembly Assembly, String [] args) an System.AppDomain.ExecuteAssembly (String assemblyFile, Evidence assemblySecurity, String [] args) beim Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly () bei System.Threading.ThreadHelper.ThreadStart_Context (Objekt Zustand) bei System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback-Callback, Objektstatus, Boolean ignoreSyncCtx) bei System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback-Callback, Objektstatus) bei System.Threading.ThreadHelper.ThreadStart ()
InnerException:
Ich war in der Lage, den verlinkten Blogeintrag mit archive.org wiederherzustellen und eine funktionierende Lösung zu finden.
Mein Ziel war es, eine EXE-Datei dynamisch in einen temporären Speicherort zu kompilieren und anschließend alle Hauptdlls in einer untergeordneten Anwendungsdomäne zu laden, damit die Hauptanwendung, die die EXE erzeugt hat, leicht aktualisiert werden kann. Der grundlegende Ansatz besteht darin, mithilfe von childAppDomain.CreateInstanceFrom einen Typ zu erstellen, der im Konstruktor den Assembly-Resolve-Ereignishandler installiert. Mein Code sah aus wie
%Vor%Und der Typ, der den benötigten AssemblyResolve-Handler erstellt (der Blogpost unten beschreibt, warum Sie einen anderen Typ benötigen)
%Vor%Hier ist der ursprüngliche Blogpost:
Anwendungsdomänen ist schwer ...
Haben Sie jemals mit der Anwendungsdomäne in .NET gearbeitet? Am Anfang scheint es gar nicht so schwierig zu sein, aber wenn Sie sie kennen lernen, fangen Sie an, all die kleinen Schwierigkeiten zu erkennen.
Alles funktioniert gut, solange Sie nicht aus dem Host-AppDomains.BaseDirectory herauskommen, aber in unserem Fall wollten wir Plug-Ins an der Stelle "C: \ My Plug-ins" bereitstellen, während die Host-Anwendung dies tun würde Führen Sie unter "C: \ Programme \ Meine App" aus, da wir möglicherweise Abhängigkeiten von der AppDomain zu einigen der Host Assemblies Probleme scheinbar unvermeidlich war.
Der Klassiker Hier ist ein einfacher Code und unser erster Versuch.
%Vor%Es scheint sehr einfach zu sein, aber weil "ApplicationBase" anders als "AppDomain.CurrentDomain.BaseDirectory" ist, haben wir etwas gefunden, was eine sehr bekannte Ausnahme zu sein scheint.
System.IO.FileNotFoundException: Die Datei 'host.Services, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null' oder eine ihrer Abhängigkeiten konnte nicht geladen werden. Das System kann die angegebene Datei nicht finden.
Wenn Sie mit irgendwelchen dynamisch ladenden Baugruppen gearbeitet haben, bin ich mir ziemlich sicher, dass Ihnen das bekannt ist. Und das Problem ist, dass "Host.Services" in der Host-Anwendungsdomäne bekannt war, da es in "C: \ Programme \ Meine App" gespeichert ist und die Anwendungsdomäne, die danach sucht, in "C: \ My Plug- ins ".
Nun, wir dachten, wir hätten es angewiesen, auch in "AppDomain.CurrentDomain.BaseDirectory" zu suchen, was "C: \ Programme \ Meine App" wäre, aber das war nicht der Fall.
AppDomain.AssemblyResolve zur Rettung? Ok, wir haben schon mit diesen Macken gearbeitet, also wussten wir, wie wir mit "AppDomain.AssemblyResolve" alle Assemblies, die die AppDomain nicht selbst bearbeiten konnte, manuell auflösen konnten.
%Vor%Das sollte richtig funktionieren, also dachten wir uns so, und wir haben uns wieder geirrt, was jetzt passiert ist, anstatt tatsächlich die Anwendungsdomäne zu initialisieren und zu benutzen, stattdessen scheitert es genau dort, wo wir den Event-Handler angeschlossen haben zum Auflösen von Baugruppen.
Auch hier sieht die Ausnahme sehr ähnlich aus wie zuvor erwähnt, aber dieses Mal kann sie nicht die Assembly finden, die den Type enthält, der den "Resolve" -Handler hat, den wir in der letzten Zeile im obigen Snippet eingerichtet haben.
AppDomain.Load dann! Ok, also offensichtlich, wenn der Event-Handler angeschlossen wird, muss die Anwendungsdomäne den Typ des Objekts kennen, das dieses Ereignis behandelt, was eigentlich ziemlich verständlich ist, wenn man darüber nachdenkt, also wenn die Anwendungsdomäne das nicht einmal findet laden wir können wirklich nichts handhaben.
Also, was kommt als nächstes? Unsere Idee war, die Anwendungsdomäne manuell anzuweisen, eine seichte Assembly zu laden, die keine anderen Abhängigkeiten hatte als die, die im GAC gefunden werden konnte, und den Hook und einen Event-Handler.
%Vor%Verwenden Sie eine sehr einfache kleine Klasse wie die folgende, und beachten Sie das seltsame Resolve-Verhalten.
%Vor%Also ja oder nein? ... NEIN! ... noch immer das gleiche Problem.
Die Dinge sind viel einfacher! Tatsächlich wurden die Dinge am Ende viel einfacher, als es uns gelungen ist, es zum Laufen zu bringen.
Ich kann nicht sagen, wie genau das .NET-Team sich vorgestellt hat, dass dies funktionieren sollte, wir konnten wirklich keine brauchbaren Dinge herausfinden, für die "PrivateBinPath" und "PrivateBinPathProbe" verwendet wurden. Nun, wir benutzen sie jetzt und haben sie so arbeiten lassen, wie wir es erwartet hatten!
Also haben wir die "AssemblyLoader" -Klasse so geändert, dass sie stattdessen so aussieht:
%Vor%Anstatt also das Ereignis anzuhängen, in dem wir die Anwendungsdomäne erstellt haben, lassen wir die Klasse dies selbst und stattdessen "CurrentDomain" tun.
Ok, warte, verursacht das nicht ein Problem beim Erstellen in der Fabrik, da es jetzt für die falsche Domain geladen wird? Nun, zum Glück können Sie Objekte innerhalb von Domänen von außen erstellen.
Das Erstellen der Domäne erfolgt nun wie folgt:
%Vor%Es ist uns nicht einmal wichtig, einen Verweis auf den "AssemblyLoader" beizubehalten, da dieser ziemlich lebendig gehalten werden sollte, indem man sich selbst an das Event anhängt.
Hoffentlich kann dies einigen helfen, die über das gleiche Problem gestolpert sind. Ich sehe viele Problemumgehungen, bei denen die Leute dann entweder einfach Plug-Ins im selben Host-Verzeichnis installieren lassen und alle notwendigen Abhängigkeiten zusammen mit dem Plug-in implementiert haben Es ist nicht etwas, von dem das Plug-in weiß, dass es davon abhängig ist und so weiter.
Das oben Genannte ermöglicht es uns zumindest, Plugins außerhalb unserer Host-Anwendungsbasis zu installieren, was ich für gut halte.
Wenn jemand das anders gelöst hat, dann bitte eine Antwort, vielleicht können wir Pro und Kontra in jeder Hinsicht finden oder einfach eine bessere Lösung finden.
Wenn Sie irgendwelche Fragen haben oder das oben genannte nicht zum Funktionieren bringen können, dann zögern Sie nicht zu fragen.
Autor: Jens Melgaard | Geposted @ Donnerstag, 01. Juli 2010 15:08 | Rückmeldung (0)
Gibt es einen Grund, warum Sie die ursprünglichen Baugruppen nicht verwenden?
Sofern Ihre ausländische App-Domäne keine Anmeldeinformationen verwendet, die den Zugriff auf die ursprünglichen Assemblys verhindern, ist die Methode AppDomain.CreateInstanceFromAndUnwrap dazu in der Lage.
Ich schlage vor, dass Sie Ihren remote ausgeführten Code in einer MarshalByRefObject-Klasse mit einer Klasse wie dieser isolieren:
%Vor%Und benutze es so:
%Vor%Dies vermeidet unnötige Probleme beim Übergeben von Rückgabewerten über den Anwendungsdomänenstatus, da DoCallBack keine Werte zurückgibt. Dies verhindert auch, dass Sie den Anwendungscode von AppDomain mit Ihrer Anwendungslogik mischen.
Schließlich müssen Sie möglicherweise AppDomain.AssemblyResolve in MyRemoteClass abfangen, damit andere Abhängigkeiten ordnungsgemäß geladen werden.
Wenn Sie die Assembly selbst laden müssen, vermeiden Sie das Laden von Bytes ... Ich würde empfehlen, zumindest das Laden über den vollständigen Assembly-Pfad zu verwenden.
Im Allgemeinen, um Probleme mit dem Laden von Baugruppen zu untersuchen Suche nach "Fusion Log Viewer" ( Ссылка ) ) und verwenden Sie das Tool, um zu sehen, wo Code versucht, Baugruppen aus zu laden.
Meine Vermutung ist, dass Sie einen wichtigen Teil der Fehlermeldung verpasst haben:
System.IO.FileNotFoundException wurde nicht behandelt Message = Datei konnte nicht geladen werden oder Assembly 'TaskExecuter, Version = 1.0.4244.31921, Kultur = neutral, PublicKeyToken = null' oder eine seiner Abhängigkeiten . Die angegebene Datei wurde vom System nicht gefunden. Quelle = mscorlib
Abgesehen davon, dass Sie Ihre Assembly nicht von einem anderen Speicherort als unter Ihrer ApplicationBase laden können, fehlt wahrscheinlich eine bestimmte Assembly, von der sie aufgelöst und geladen werden kann.
Wenn Sie mit dem Laden von Bytes beginnen, sollten Sie sich übrigens die Assemblys ansehen, die in Ihrer Domain geladen sind. Die abhängige Assembly wird möglicherweise bereits geladen, die Abhängigkeit kann jedoch nicht automatisch aufgelöst werden. Wenn Sie dieselbe Baugruppe zweimal laden, sind ihre Typen inkompatibel. Sie werden lustige CastExceptions erhalten, die sagen, dass ein Objekt von YourClass nicht in YourClass umgewandelt werden kann.
Sie können versuchen, einen AssemblyResolve-Event-Handler für Ihre Domain zu registrieren, aber damit enden Sie leicht mit etwas Black Magic-Zauberzeug aus .dll-Hölle. Wenn alles andere schief geht und du zur .dll-Hölle gehst, triff mich hier: Sie müssen das AssemblyResolve-Ereignis verknüpfen, wenn DisallowApplicationBaseProbing = true