So laden Sie alle bereitgestellten Assemblies für eine Anwendungsdomäne vorab

UPDATE: ich habe jetzt eine Lösung ich bin viel glücklicher mit, dass zwar nicht die Lösung all der Probleme, die ich Fragen über, es lässt den Weg frei, dies zu tun. Ich habe aktualisiert, meine eigenen Antworten zu reflektieren.

Ursprüngliche Frage

Gegeben, eine App-Domäne, es gibt viele verschiedene Orte, dass die Fusion (die .Net-assembly-loader) wird die Sonde für eine bestimmte Baugruppe. Offensichtlich nehmen wir diese Funktionalität für selbstverständlich, und, da die gesuchten zu sein scheint, eingebettet in die .Net-runtime (Assembly._nLoad interne Methode scheint der entry-Punkt bei der Reflect-Laden - und ich gehe davon aus, dass implizite laden ist wahrscheinlich unter den gleichen zugrunde liegenden Algorithmus), als Entwickler, die wir nicht scheinen, um zu gewinnen, Zugang zu den Suchpfaden.

Mein problem ist, dass ich eine Komponente, das eine Menge von dynamischen Typ Auflösung, und die muss in der Lage sein, um sicherzustellen, dass alle vom Benutzer bereitgestellten Baugruppen für eine bestimmte Anwendungsdomäne sind bereits geladen, bevor es mit seiner Arbeit beginnt. Ja, es verlangsamt Systemstart - aber die Vorteile, die wir von dieser Komponente völlig outweight.

Den basic-loading-Algorithmus habe ich bereits geschrieben, ist wie folgt. Es tief scannt eine Reihe von Ordnern für jeden .dll (.exes sind ausgeschlossen im moment), und benutzt die Versammlung.LoadFrom um die dll zu laden, wenn es AssemblyName nicht gefunden werden kann in dem Satz von Assemblys bereits geladen wird in die Anwendungsdomäne (in diesem implementiert ist ineffizient, aber es kann später optimiert):

void PreLoad(IEnumerable<string> paths)
{
  foreach(path p in paths)
  {
    PreLoad(p);
  }
}

void PreLoad(string p)
{
  //all try/catch blocks are elided for brevity
  string[] files = null;

  files = Directory.GetFiles(p, "*.dll", SearchOption.AllDirectories);

  AssemblyName a = null;
  foreach (var s in files)
  {
    a = AssemblyName.GetAssemblyName(s);
    if (!AppDomain.CurrentDomain.GetAssemblies().Any(
        assembly => AssemblyName.ReferenceMatchesDefinition(
        assembly.GetName(), a)))
      Assembly.LoadFrom(s);
  }    
}

LoadFrom verwendet wird, denn ich habe festgestellt, dass mit Load() kann führen zu doppelten Assemblys geladen werden, die durch die Fusion, wenn es Sonden, ist es nicht geladen, von wo erwartet er es zu finden.

So, in diesem Ort, alles, was ich jetzt tun müssen, ist, um eine Liste in der Rangfolge (von der höchsten zur niedrigsten) der Suchpfade, die Fusion zu gehen, um mithilfe bei der Suche nach einer assembly. Dann kann ich einfach Durchlaufen.

GAC ist irrelevant für diese, und ich bin nicht daran interessiert, in jeder Umgebung-driven Feste Wege, die Fusion verwenden könnte - nur die Pfade, die zusammengetragen werden können, von der AppDomain, in denen Baugruppen ausdrücklich bereitgestellt für die app.

Meine erste iteration dieses einfach Anwendungsdomäne verwendet.BaseDirectory. Dies funktioniert für Dienstleistungen in form von apps und Konsolen-apps.

Funktioniert es nicht für eine Asp.Net website, jedoch, da es mindestens zwei Haupt-Standorten der Anwendungsdomäne.DynamicDirectory (wo Asp.Net stellen Sie die dynamisch generierte Seite Klassen und Assemblys, die die Aspx-Seite code-Referenzen), und dann wird die Website in den Ordner Bin -, die entdeckt werden kann, von der Anwendungsdomäne.SetupInformation.PrivateBinPath Eigenschaft.

So, ich habe jetzt funktionierenden code für die grundlegenden Arten von apps jetzt (Sql Server-gehostet AppDomains sind eine andere Geschichte, da das Dateisystem virtualisiert) - aber ich bin auf ein Interessantes Problem vor ein paar Tagen, wo dieser code funktioniert einfach nicht: der nUnit-test-runner.

Diese nutzt sowohl Schatten-Kopieren (also mein Algorithmus werden müssten, entdecken und laden Sie aus dem Schatten-Kopie-drop-Ordner, nicht die aus dem bin-Ordner) und es setzt den PrivateBinPath als relativ zum Basis-Verzeichnis.

Und natürlich gibt es viele andere hosting-Szenarien, die ich wahrscheinlich noch nicht überlegt, aber die muss gültig sein, weil sonst die Fusion würde choke beim laden der Baugruppen.

Ich will aufhören, das Gefühl um und die Einführung von hack nach hack, um Platz für diese neuen Szenarien, wie Sie auftauchen, was ich will, ist, angesichts einer Anwendungsdomäne und Ihre setup-Informationen, die Fähigkeit zu produzieren, diese Liste der Ordner, die ich Scannen sollte, um abholen alle DLLs, die geladen werden; unabhängig davon, wie die AppDomain ist setup. Wenn Fusion können Sie sehen, wie alle die gleichen, dann sollte mein code.

Natürlich, ich könnte haben, zu ändern, den Algorithmus, wenn .Netto verpasst seiner Interna - das ist nur ein Kreuz ich werde zu tragen haben. Ebenso, ich bin glücklich, zu prüfen, SQL Server und alle anderen ähnlichen Umgebungen Rand-Fällen, die weiterhin nicht unterstützt für jetzt.

Irgendwelche Ideen!?

InformationsquelleAutor der Frage Andras Zoltan | 2010-06-11

Schreibe einen Kommentar