2013-11-26 3 views
10

Ich habe zwei Baugruppen: App und . App Referenzen , aber CopyLocal ist auf false eingestellt, da wird dynamisch von App geladen werden. HierWarum benötige ich einen AssemblyResolve-Handler für eine Assembly, die bereits geladen ist?

ist der Code in AddOn:

namespace AddOn 
{ 
    public class AddOnClass 
    { 
     public static void DoAddOnStuff() 
     { 
      Console.WriteLine("AddOn is doing stuff."); 
     } 
    } 
} 

und hier ist der Code in App:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Assembly.LoadFrom(@"..\..\..\AddOn\bin\Debug\AddOn.dll"); 

     // Without this event handler, we get a FileNotFoundException. 
     // AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => 
     // { 
     //  return AppDomain.CurrentDomain.GetAssemblies() 
     //      .FirstOrDefault(a => a.FullName == e.Name); 
     //}; 

     CallAddOn(); 
    } 

    [MethodImpl(MethodImplOptions.NoInlining)] 
    private static void CallAddOn() 
    { 
     AddOnClass.DoAddOnStuff(); 
    } 
} 

Was ich nicht verstehe ist, warum der Code nicht mit der AssemblyResolve funktioniert Handler kommentiert in Main(). Bei Ausführung in Visual Studio bricht der Debugger CallAddOn() mit einem FileNotFoundException. Warum beschwert es sich? Die Assembly wird geladen, und es ist die exakt gleiche Version (d. H. Die gleiche Datei auf der Festplatte), auf die von App verwiesen wurde.

Ich habe das Gefühl, dass es ein grundlegendes Konzept gibt, das ich hier nicht richtig verstehe. Der kommentierte AssemblyResolve Handler funktioniert gut, aber es scheint wie ein Hack und ich verstehe nicht, warum ich es brauche, weil es so aussieht, als würde es etwas Triviales tun.

+1

Sie tun das falsch. Wenn Sie zulassen, dass Add-Ons in Ihrem Programm verwendet werden, kennen Sie * den Typ der Klasse im Add-On nicht. Es wurde von einem anderen Programmierer geschrieben. Sie sollten also ziemlich an dem Rückgabewert von LoadFrom() interessiert sein, Sie werden beispielsweise Assembly.GetType() verwenden, um einen Typ zu ermitteln. –

+0

Es ist ein Addon, das auf ein anderes Addon verweist, weil es sich auf diese Funktionalität verlässt. – RobSiklos

+0

Das ist kein Addon, nur eine normale abhängige Assembly. Sie verwenden immer "Copy Local = True", um sicherzustellen, dass die CLR die Assembly automatisch finden kann, ohne dass Sie Hilfe benötigen. Welches ist die Standardeinstellung? –

Antwort

9

Der Grund ist, dass es mehrere Assembly laden Kontexte gibt. Der Kontext, in den eine Assembly geladen wird, beeinflusst, wie sie verwendet werden kann. Wenn eine Assembly von der Laufzeitumgebung mithilfe des Standardtestmechanismus geladen wird, wird sie in den so genannten Load-Kontext versetzt. Dies ist der Kontext, der verwendet wird, wenn Sie eine Baugruppe über Assembly.Load laden. Sie haben die Assembly mit LoadFrom geladen, die ihren eigenen Kontext verwendet. Beim Prüfen wird der LoadFrom-Kontext nicht untersucht, und die Datei befindet sich nicht im Prüfpfad. Daher müssen Sie sie für die Laufzeit auflösen. Dies ist jedoch nicht symmetrisch. Wenn eine Assembly im Ladekontext geladen wird, lädt LoadFrom sie zuerst von dort (vorausgesetzt, die Identität ist identisch. Bei nicht signierten Assemblys ist der Pfad Teil der Identität.). Ich werde feststellen, dass es mehrere Kontexte gibt, einschließlich ReflectionOnlyLoad und ReflectionOnlyLoadFrom. LoadFile lädt eine Assembly ohne Kontext, d. H. Alle Abhängigkeiten müssen manuell geladen werden.

Wenn Sie möchten, dass Baugruppen im Ladekontext aufgelöst werden, sie aber außerhalb des Standardprüfpfads der Anwendung existieren, können Sie dies auch über die Konfiguration tun. Verwenden Sie entweder das <codebase>-Element einer Baugruppenbindungsumleitung oder das privatePath-Attribut des Elements <probing>.

Lesen Sie this für weitere Informationen. Es gibt auch einige Blog-Posts von Suzanne Cook von einer Weile zurück auf Assembly laden und Kontexte (siehe , here und here).

Verwandte Themen