Wie wird ein Projekt erstellt / bereitgestellt, das mehrere Versionen derselben Assembly erfordert?

8

Ich arbeite an einem Projekt, das conflict.dll Version 6.2 verwendet, aber das Projekt verwendet auch helper.dll, die conflict.dll Version 5.8 verwendet.

Ich könnte 6.2 und 5.8 in den GAC installieren, aber ich möchte dieses Projekt xcopy bereitstellen lassen. Ich glaube, dass .net wie folgt nach den Assemblys im Anwendungsverzeichnis suchen wird: \ bin \ konflikt.dll (6.2) \ bin \ 5.8 \ conflict.dll (5.8)

Aber an dieser Stelle, wie füge ich einen Verweis auf beide Versionen von conflict.dll im Projekt hinzu, und wie stelle ich dann sicher, dass die alte conflict.dll nach \ bin \ 5.8 implementiert? Erstelle ich eine Build-Aktion oder gibt es einen anderen Weg?

Danke

    
djmc 05.09.2010, 19:41
quelle

3 Antworten

1

Zur Unterstützung von Darin's Antwort müssen Sie natürlich solche Probleme mit mehreren Versionen beseitigen. Seine Lösung, eine verbindliche Umleitung zu verwenden, ist eine gute - +1 dort. Ich kann eine Lösung anbieten, mit der Sie beides behalten können, wenn es absolut notwendig ist, aber Sie müssen ein wenig Code schreiben.

Das einzige wirkliche Problem, das Sie hier haben, ist, dass die beiden bereitgestellten Dateinamen identisch sein müssen, damit sie vom Loader standardmäßig übernommen werden. Du könntest wirklich entsetzlich schummeln und einfach die 5.8 dll als Conflict.exe einsetzen, damit sie Seite an Seite Conflict.dll (und neuer) sitzen kann und du würdest finden, dass es funktioniert.

Auch nach den Links von Darin's Antwort kommen Sie zu diesem Thema MSDN Thema auf Sondieren . Basierend auf diesem Inhalt können Sie einfach die 5.8-DLL in bin \ Content \ Content.dll bereitstellen. Wenn die Laufzeitumgebung danach sucht, wird sie automatisch in diesem Unterordner angezeigt.

Allerdings - das ist keine gute Lösung:)

BEARBEITEN - NEUE LÖSUNG

Wenn beide Versionen von Conflict.dll bereits signiert sind, haben Sie tatsächlich versucht, eine der Versionen mit einem etwas anderen Namen zu implementieren? Ich habe gerade eine Winforms-App mit zwei Assembly-Referenzen auf verschiedene Versionen derselben (signierten) Assembly eingerichtet. Dies führt zu einigen Problemen mit dem Build, da die zuletzt referenzierte Version im bin-Ordner bereitgestellt wird und die andere nicht (Sie müssen also beides manuell kopieren; eines davon entsprechend umbenennen). Dann versuche ich, die App auszuführen, die ein Meldungsfeld mit zwei konstanten Strings anzeigt. eine von jeder Version der Baugruppe. Es funktioniert absolut gut.

Laden Sie hier eine Demo herunter - mach es nicht (sonst musst du die Datei umbenennen); Öffnen Sie einfach den bin \ debug-Ordner der Formular-App und führen Sie die exe aus.

ClassLibrary1.dll und ClassLibary1vanything.dll sind v1.0.0.0 und v2.0.0.0 einer Assembly mit ansonsten demselben Namen und demselben öffentlichen Schlüssel. Trotz der Tatsache, dass classlibrary1vanything.dll den falschen Dateinamen hat, funktioniert es (wahrscheinlich, weil es signiert ist).

In der app.config habe ich einen Codebasis-Hinweis eingefügt und dachte, dass das der Grund war, warum es funktionierte (ursprünglich habe ich es als einen anderen Dateinamen bereitgestellt), aber dann habe ich es auskommentiert und es funktionierte immer noch. Die Codebasis ist wahrscheinlich am nützlichsten, wenn die Assembly in einem Unterordner oder an einem anderen Speicherort bereitgestellt werden muss.

ORIGINAL TEXT

Ich habe versucht, die zweite der genannten Optionen in diesem Support-Artikel von MS zu bekommen, aber es funktioniert scheint nicht zu wollen.

Zweifellos gibt es einen cleveren Weg, es aus der Box zu machen, aber da ich nicht schlau genug bin, es (noch) zu finden, würde ich stattdessen die dritte der Optionen, die in der oben erwähnten Unterstützung angezeigt werden, verschönern Thema und hook in das AssemblyResolve -Ereignis der App-Domäne.

Wenn Sie Ihre eigene Konfiguration (wahrscheinlich nur in appSettings) für den vollständigen Namen der Assembly hinzufügen, die an einen anderen Dateinamen gebunden werden soll, können Sie in Ihrer AssemblyResolve-Ereignisbehandlungsroutine den Namen der Assembly abrufen, die geladen werden soll um zu sehen, ob es in deiner Konfiguration ist. Wenn dies der Fall ist, greifen Sie nach dem Speicherort und verwenden Sie Assembly.LoadFrom, um es zu laden.

Wenn Sie so etwas an Ort und Stelle haben, fügen Sie einfach einen Eintrag für den Namen der Conflict v5.8-Assembly hinzu und den Dateinamen, den die App verwenden soll.

Ich weiß nicht, welche Art von App Sie bereitstellen, aber in den win-Formularen sind die Konsolen-Apps und Dienste AppDomain.CurrentDomain.BaseDirectory gleich dem bin-Ordner und Sie können diesen mit dem Dateinamen verbinden, den Sie laden möchten . Websites sind ein wenig komplizierter.

Sollte ein Leckerbissen sein.

    
Andras Zoltan 05.09.2010, 21:32
quelle
14
___ qstnhdr ___ Wie wird ein Projekt erstellt / bereitgestellt, das mehrere Versionen derselben Assembly erfordert? ___ tag123net ___ Das .NET-Framework ist ein Software-Framework, das hauptsächlich für das Microsoft Windows-Betriebssystem entwickelt wurde. Es enthält eine Implementierung der Basisklassenbibliothek, Common Language Runtime (allgemein als CLR bezeichnet), Common Type System (allgemein als CTS bezeichnet) und Dynamic Language Runtime. Es unterstützt viele Programmiersprachen, einschließlich C #, VB.NET, F # und C ++ / CLI. NICHT für Fragen zu .NET Core verwenden. ___ tag123visualstudio ___ Verwenden Sie dieses Tag, wenn Sie eine bestimmte Frage zu Visual Studio-Funktionen und -Funktionen haben. Verwenden Sie diesen Tag NICHT bei Fragen zu Code, der nur zufällig in Visual Studio geschrieben wurde. Erwägen Sie, den genauen Technologiebereich zu markieren, auf den Ihre Frage verweist, und kennzeichnen Sie auch eine spezifischere Version von Visual Studio. Bitte geben Sie Ihre genaue VS-Version, Edition und Update-Ebene in Ihrer Frage an. ___ answer3647693 ___
  

Ich glaube, .net wird nach dem suchen   Baugruppen in der Anwendungsablage   Verzeichnis wie folgt: \ bin \ conflict.dll   (6.2) \ bin \ 5.8 \ conflict.dll (5.8)

Nein, das ist falsch. Ich würde Ihnen empfehlen, diesen Artikel zu lesen, um mehr darüber zu erfahren, welche Heuristik die CLR verwendet zum Sondieren .

Da gesagt wird, können Sie nicht zwei verschiedene Versionen derselben Assembly in derselben Anwendungsdomäne laden Sie können verschiedene Versionen derselben Assembly in dieselbe Anwendungsdomäne laden, aber es ist als schlechte Praxis angesehen und sollte vermieden werden. In Ihrem Fall bedeutet dies, dass Sie auswählen müssen, welche Version der in Konflikt stehenden Assembly Sie verwenden möchten. Sie haben ein paar Möglichkeiten:

  1. Kompiliere lib\ neu, um die neueste Version von app/web.config zu verwenden (Ich werde definitiv mit dieser Version gehen, wenn ich den Quellcode für xcopy habe).
  2. Wählen Sie die gewünschte Version von bin\Conflict und wenden Sie eine % co_de-Datei an % in Ihrer Konfigurationsdatei. Zum Beispiel, wenn Sie die neueste Version verwenden möchten:

    %Vor%

Dadurch wird die CLR angewiesen, die Version 6.2 von Include in Project zu laden, wenn sie versucht, Referenzen für %code% aufzulösen. Beachten Sie, dass diese Technik nicht funktioniert, wenn die beiden Versionen stark mit verschiedenen Schlüsseln signiert sind. Offensichtlich als %code% wurde gegen Version 5.8 kompiliert, wenn Sie irgendwelche Unterschiede haben (fehlende Methoden, verschiedene Methodensignaturen), erhalten Sie eine Laufzeitausnahme beim Versuch, eine in Konflikt stehende Methode aufzurufen, also tun Sie dies nur, wenn Sie absolut sicher sind, was Sie tun .

Fazit: Egal welchen Pfad du wählst, du musst %code% im Ordner bin eine einzige Version von %code% .

haben     
___ qstntxt ___

Ich arbeite an einem Projekt, das conflict.dll Version 6.2 verwendet, aber das Projekt verwendet auch helper.dll, die conflict.dll Version 5.8 verwendet.

Ich könnte 6.2 und 5.8 in den GAC installieren, aber ich möchte dieses Projekt xcopy bereitstellen lassen. Ich glaube, dass .net wie folgt nach den Assemblys im Anwendungsverzeichnis suchen wird: \ bin \ konflikt.dll (6.2) \ bin \ 5.8 \ conflict.dll (5.8)

Aber an dieser Stelle, wie füge ich einen Verweis auf beide Versionen von conflict.dll im Projekt hinzu, und wie stelle ich dann sicher, dass die alte conflict.dll nach \ bin \ 5.8 implementiert? Erstelle ich eine Build-Aktion oder gibt es einen anderen Weg?

Danke

    
___ answer0936596 ___

Nach vielen Stunden des Suchens und Fluchens fand ich eine Lösung, die funktioniert und einfach und zuverlässig zu implementieren ist.

Das Problem hat wie alle anderen Antworten darauf hingewiesen, dass alle folgenden Punkte erfüllt sein müssen:

  1. Beide Versionen der DLL müssen denselben Namen haben, sonst wird sich die Laufzeitumgebung darüber beschweren, dass der Name nicht mit dem Manifest übereinstimmt.
  2. Die Laufzeitumgebung muss in der Lage sein, beide Assemblies im Suchpfad zu finden.
  3. Eine Versionsumleitung ist aufgrund von Änderungen nicht möglich.
  4. AppDomain.ResolveAssembly wird in diesem Beispiel nie aufgerufen, da die Assembly bereits einmal geladen wurde.

Die Lösung ist in den folgenden Schritten verfügbar:

  1. Erstellen Sie ein Verzeichnis in Ihrem Lösungsverzeichnis, z. B. %code% with diese Hierarchie:

    lib \ Konflikt \ v1 \ Conflict.dll
    lib \ Konflikt \ v2 \ Conflict.dll

  2. Fügen Sie Ihrem %code% Folgendes hinzu:

%Vor%
  1. Fügen Sie ein Post-Build-Ereignis mit einem %code% hinzu:

    xcopy $ (SolutionDir) \ lib $ (TargetDir) / Y / S

  2. Einmal erstellen, damit die Dateien kopiert werden. Klicken Sie auf "Projekt - & gt; Alle Dateien anzeigen". Klicken Sie mit der rechten Maustaste auf %code% und machen Sie %code% (das spart Ihnen den Code). Dies ist erforderlich, damit die Dateien bereitgestellt werden, wenn Sie eine Webanwendung packen.

Fertig!

    
___ tag123assemblies ___ Assemblies sind Sammlungen von kompilierten .Net-Typen und -Ressourcen, die in einer logischen und physischen Einheit gruppiert sind (in Form einer .dll-Datei oder einer .exe-Datei). ___ answer3647889 ___

Zur Unterstützung von Darin's Antwort müssen Sie natürlich solche Probleme mit mehreren Versionen beseitigen. Seine Lösung, eine verbindliche Umleitung zu verwenden, ist eine gute - +1 dort. Ich kann eine Lösung anbieten, mit der Sie beides behalten können, wenn es absolut notwendig ist, aber Sie müssen ein wenig Code schreiben.

Das einzige wirkliche Problem, das Sie hier haben, ist, dass die beiden bereitgestellten Dateinamen identisch sein müssen, damit sie vom Loader standardmäßig übernommen werden. Du könntest wirklich entsetzlich schummeln und einfach die 5.8 dll als %code% einsetzen, damit sie Seite an Seite %code% (und neuer) sitzen kann und du würdest finden, dass es funktioniert.

Auch nach den Links von Darin's Antwort kommen Sie zu diesem Thema MSDN Thema auf Sondieren . Basierend auf diesem Inhalt können Sie einfach die 5.8-DLL in bin \ Content \ Content.dll bereitstellen. Wenn die Laufzeitumgebung danach sucht, wird sie automatisch in diesem Unterordner angezeigt.

Allerdings - das ist keine gute Lösung:)

BEARBEITEN - NEUE LÖSUNG

Wenn beide Versionen von Conflict.dll bereits signiert sind, haben Sie tatsächlich versucht, eine der Versionen mit einem etwas anderen Namen zu implementieren? Ich habe gerade eine Winforms-App mit zwei Assembly-Referenzen auf verschiedene Versionen derselben (signierten) Assembly eingerichtet. Dies führt zu einigen Problemen mit dem Build, da die zuletzt referenzierte Version im bin-Ordner bereitgestellt wird und die andere nicht (Sie müssen also beides manuell kopieren; eines davon entsprechend umbenennen). Dann versuche ich, die App auszuführen, die ein Meldungsfeld mit zwei konstanten Strings anzeigt. eine von jeder Version der Baugruppe. Es funktioniert absolut gut.

Laden Sie hier eine Demo herunter - mach es nicht (sonst musst du die Datei umbenennen); Öffnen Sie einfach den bin \ debug-Ordner der Formular-App und führen Sie die exe aus.

ClassLibrary1.dll und ClassLibary1vanything.dll sind v1.0.0.0 und v2.0.0.0 einer Assembly mit ansonsten demselben Namen und demselben öffentlichen Schlüssel. Trotz der Tatsache, dass classlibrary1vanything.dll den falschen Dateinamen hat, funktioniert es (wahrscheinlich, weil es signiert ist).

In der app.config habe ich einen Codebasis-Hinweis eingefügt und dachte, dass das der Grund war, warum es funktionierte (ursprünglich habe ich es als einen anderen Dateinamen bereitgestellt), aber dann habe ich es auskommentiert und es funktionierte immer noch. Die Codebasis ist wahrscheinlich am nützlichsten, wenn die Assembly in einem Unterordner oder an einem anderen Speicherort bereitgestellt werden muss.

ORIGINAL TEXT

Ich habe versucht, die zweite der genannten Optionen in diesem Support-Artikel von MS zu bekommen, aber es funktioniert scheint nicht zu wollen.

Zweifellos gibt es einen cleveren Weg, es aus der Box zu machen, aber da ich nicht schlau genug bin, es (noch) zu finden, würde ich stattdessen die dritte der Optionen, die in der oben erwähnten Unterstützung angezeigt werden, verschönern Thema und hook in das %code% -Ereignis der App-Domäne.

Wenn Sie Ihre eigene Konfiguration (wahrscheinlich nur in appSettings) für den vollständigen Namen der Assembly hinzufügen, die an einen anderen Dateinamen gebunden werden soll, können Sie in Ihrer AssemblyResolve-Ereignisbehandlungsroutine den Namen der Assembly abrufen, die geladen werden soll um zu sehen, ob es in deiner Konfiguration ist. Wenn dies der Fall ist, greifen Sie nach dem Speicherort und verwenden Sie Assembly.LoadFrom, um es zu laden.

Wenn Sie so etwas an Ort und Stelle haben, fügen Sie einfach einen Eintrag für den Namen der Conflict v5.8-Assembly hinzu und den Dateinamen, den die App verwenden soll.

Ich weiß nicht, welche Art von App Sie bereitstellen, aber in den win-Formularen sind die Konsolen-Apps und Dienste %code% gleich dem bin-Ordner und Sie können diesen mit dem Dateinamen verbinden, den Sie laden möchten . Websites sind ein wenig komplizierter.

Sollte ein Leckerbissen sein.

    
___
georgiosd 07.06.2012 17:12
quelle
3
  

Ich glaube, .net wird nach dem suchen   Baugruppen in der Anwendungsablage   Verzeichnis wie folgt: \ bin \ conflict.dll   (6.2) \ bin \ 5.8 \ conflict.dll (5.8)

Nein, das ist falsch. Ich würde Ihnen empfehlen, diesen Artikel zu lesen, um mehr darüber zu erfahren, welche Heuristik die CLR verwendet zum Sondieren .

Da gesagt wird, können Sie nicht zwei verschiedene Versionen derselben Assembly in derselben Anwendungsdomäne laden Sie können verschiedene Versionen derselben Assembly in dieselbe Anwendungsdomäne laden, aber es ist als schlechte Praxis angesehen und sollte vermieden werden. In Ihrem Fall bedeutet dies, dass Sie auswählen müssen, welche Version der in Konflikt stehenden Assembly Sie verwenden möchten. Sie haben ein paar Möglichkeiten:

  1. Kompiliere helper.dll neu, um die neueste Version von conflict.dll zu verwenden (Ich werde definitiv mit dieser Version gehen, wenn ich den Quellcode für helper.dll habe).
  2. Wählen Sie die gewünschte Version von conflict.dll und wenden Sie eine % co_de-Datei an % in Ihrer Konfigurationsdatei. Zum Beispiel, wenn Sie die neueste Version verwenden möchten:

    %Vor%

Dadurch wird die CLR angewiesen, die Version 6.2 von <bindingRedirect> zu laden, wenn sie versucht, Referenzen für conflict.dll aufzulösen. Beachten Sie, dass diese Technik nicht funktioniert, wenn die beiden Versionen stark mit verschiedenen Schlüsseln signiert sind. Offensichtlich als helper.dll wurde gegen Version 5.8 kompiliert, wenn Sie irgendwelche Unterschiede haben (fehlende Methoden, verschiedene Methodensignaturen), erhalten Sie eine Laufzeitausnahme beim Versuch, eine in Konflikt stehende Methode aufzurufen, also tun Sie dies nur, wenn Sie absolut sicher sind, was Sie tun .

Fazit: Egal welchen Pfad du wählst, du musst helper.dll im Ordner bin eine einzige Version von xcopy .

haben     
Darin Dimitrov 05.09.2010 20:32
quelle

Tags und Links