So löst NuGet Paketabhängigkeiten auf
Jedes Mal, wenn ein Paket installiert oder neu installiert wird, einschließlich der Installation als Teil eines Wiederherstellens Prozess, installiert NuGet auch alle zusätzlichen Pakete, von denen dieses erste Paket abhängt.
Diese unmittelbaren Abhängigkeiten können dann auch eigene Abhängigkeiten haben, die weiterhin eine beliebige Tiefe aufweisen können. Dadurch wird ein Abhängigkeitsdiagramm erzeugt, das die Beziehungen zwischen Paketen auf allen Ebenen beschreibt.
Wenn mehrere Pakete dieselbe Abhängigkeit aufweisen, kann die gleiche Paket-ID mehrmals im Diagramm angezeigt werden, möglicherweise mit unterschiedlichen Versionsbeschränkungen. Es kann jedoch nur eine Version eines bestimmten Pakets in einem Projekt verwendet werden, sodass NuGet auswählen muss, welche Version verwendet wird. Der genaue Prozess hängt vom verwendeten Paketverwaltungsformat ab.
Abhängigkeitsauflösung mit PackageReference
Beim Installieren von Paketen in Projekten mit dem PackageReference-Format fügt NuGet Verweise auf ein flaches Paketdiagramm in der entsprechenden Datei hinzu und löst Konflikte im Voraus. Dieser Prozess wird als transitive Wiederherstellungbezeichnet. Das erneute Installieren oder Wiederherstellen von Paketen ist dann ein Prozess des Herunterladens der im Diagramm aufgeführten Pakete, was zu schnelleren und vorhersehbareren Builds führt.
Sie können auch unverankerte Versionen wie 2.8.*nutzen, um zu vermeiden, dass das Projekt geändert wird, um die neueste Version eines Pakets zu verwenden. Bei Verwendung variabler Versionen wird empfohlen, die -Sperrdateifunktionalität zu aktivieren, um die Wiederholbarkeit sicherzustellen.
Wenn der NuGet-Wiederherstellungsvorgang vor einem Build ausgeführt wird, werden abhängigkeiten zuerst im Arbeitsspeicher aufgelöst, und anschließend wird das resultierende Diagramm in eine Datei mit dem Namen project.assets.json
geschrieben.
Die Assets-Datei befindet sich in MSBuildProjectExtensionsPath
, welche standardmäßig im 'obj'-Ordner des Projekts liegt.
MSBuild liest diese Datei und übersetzt sie in eine Reihe von Ordnern, in denen potenzielle Verweise gefunden werden können, und fügt sie dann der Projektstruktur im Arbeitsspeicher hinzu.
Die project.assets.json
Datei ist temporär und sollte nicht zur Quellcodeverwaltung hinzugefügt werden. Sie ist standardmäßig in .gitignore
und .tfignore
aufgeführt. Siehe Pakete und Quellenkontrolle.
Regeln zur Abhängigkeitsauflösung
Transitive Wiederherstellung wendet vier Hauptregeln zum Auflösen von Abhängigkeiten an: niedrigste anwendbare Version, schwebende Versionen, direkte Abhängigkeiten gewinnenund verwandte Abhängigkeiten.
Niedrigste anwendbare Version
Die niedrigste anwendbare Versionsregel stellt die niedrigste mögliche Version eines Pakets wieder her, wie durch seine Abhängigkeiten definiert. Sie gilt auch für Abhängigkeiten von der Anwendung oder der Klassenbibliothek, es sei denn, sie wird als flexibledeklariert.
In der folgenden Abbildung wird z. B. 1.0-Beta als niedriger als 1.0 betrachtet, sodass NuGet die Version 1.0 auswäht:
In der nächsten Abbildung ist Version 2.1 nicht für den Feed verfügbar, aber da die Versionseinschränkung >= 2.1 NuGet die nächste niedrigste Version auswählt, die sie finden kann, in diesem Fall 2.2:
Wenn eine Anwendung eine genaue Versionsnummer angibt, z. B. 1.2, die für den Feed nicht verfügbar ist, schlägt NuGet beim Versuch, das Paket zu installieren oder wiederherzustellen, fehl:
Schwebende Versionen
Eine fließende Abhängigkeitsversion wird mit dem Zeichen * angegeben. Beispiel: 6.0.*
. Diese Versionsspezifikation besagt "die neueste Version von 6.0.x verwenden"; 4.*
bedeutet "die neueste Version von 4.x verwenden". Durch die Verwendung einer unverankerten Version werden Änderungen an der Projektdatei reduziert, während sie mit der neuesten Version einer Abhängigkeit auf dem neuesten Stand bleiben.
Fließende Versionen können nur auf Projektebene festgelegt werden.
Bei Verwendung einer unverankerten Version löst NuGet die höchste Version eines Pakets auf, das dem Versionsmuster entspricht, z. B. 6.0.*
ruft die höchste Version eines Pakets ab, das mit 6.0 beginnt:
Version | Versionen, die auf dem Server vorhanden sind | Auflösung | Grund | Notizen |
---|---|---|---|---|
* | 1.1.0 1.1.1 1.2.0 1.3.0-Alpha |
1.2.0 | Die höchste stabile Version. | |
1.1.* | 1.1.0 1.1.1 1.1.2-Alpha 1.2.0-Alpha |
1.1.1 | Die höchste stabile Version, die das angegebene Muster respektiert. | |
*-* | 1.1.0 1.1.1 1.1.2-Alpha 1.3.0-Beta |
1.3.0-Beta | Die höchste Version einschließlich der nicht stabilen Versionen. | Verfügbar in Visual Studio, Version 16.6, NuGet Version 5.6, .NET Core SDK Version 3.1.300 |
1.1.*-* | 1.1.0 1.1.1 1.1.2-Alpha 1.1.2-Beta 1.3.0-Beta |
1.1.2-Beta | Die höchste Version, die das Muster respektiert und die nicht stabilen Versionen enthält. | Verfügbar in Visual Studio, Version 16.6, NuGet Version 5.6, .NET Core SDK Version 3.1.300 |
1.2.0-rc.* | 1.1.0 1.2.0-rc.1 1.2.0-rc.2 1.2.0 |
1.2.0 | Obwohl es sich um einen Versionsbereich mit einer Vorabversion handelt, sind stabile Versionen zulässig, wenn sie mit dem stabilen Teil übereinstimmen. Da 1.2.0 > 1.2.0-rc.2 gewählt wird, ist sie die gewählte Version. |
Anmerkung
Die dynamische Versionsauflösung berücksichtigt nicht, ob ein Paket vorhanden ist oder nicht. Die schwebende Versionsauflösung wird lokal durchgeführt, wenn die Bedingungen mit Paketen im Globalen Paketordner erfüllt werden können.
Direkte Abhängigkeit gewinnt
Wenn das Paketdiagramm für eine Anwendung unterschiedliche Versionen eines Pakets in demselben Untergraph enthält und eine dieser Versionen eine direkte Abhängigkeit in diesem Untergraph ist, wird diese Version für dieses Untergraph ausgewählt, und der Rest wird ignoriert. Dieses Verhalten ermöglicht es einer Anwendung, eine bestimmte Paketversion im Abhängigkeitsdiagramm außer Kraft zu setzen.
Im folgenden Beispiel hängt die Anwendung direkt von Paket B mit einer Versionsbeschränkung von >=2.0.0 ab. Die Anwendung hängt auch von Paket A ab, die wiederum von Paket B abhängt, aber mit einer >=1.0.0-Einschränkung. Da die Abhängigkeit von Package B 2.0.0 direkte Abhängigkeit von der Anwendung im Diagramm ist, wird diese Version verwendet:
Warnung
Die Regel, dass Direktabhängigkeit gewinnt, kann zu einem Downgrade der Paketversion führen und dadurch möglicherweise andere Abhängigkeiten im Graphen beeinträchtigen. Wenn ein Paket herabgestuft wird, fügt NuGet eine Warnung hinzu, um den Benutzerzu benachrichtigen.
Diese Regel führt auch zu einer höheren Effizienz mit einem großen Abhängigkeitsdiagramm. Wenn eine engere Abhängigkeit im selben Untergraphen eine höhere Version als ein weiteres aufweist, ignoriert NuGet diese Abhängigkeit, und NuGet ignoriert auch alle verbleibenden Abhängigkeiten von diesem Zweig des Diagramms.
Im folgenden Diagramm, z. B. weil Package C 2.0.0 verwendet wird, ignoriert NuGet alle Verzweigungen in diesem Untergraphen, die auf eine frühere Version von Package C verweisen:
Durch diese Regel versucht NuGet, die Absicht des Paketautors zu berücksichtigen. Im folgenden Diagramm hat der Autor von Package A das Paket C von Version 2.0.0 auf Version 1.0.0 explizit herabgestuft.
Der Anwendungsbesitzer kann das Upgrade von Package C auf eine Version höher als 2.0.0 auswählen und somit keine weitere Herabstufung der Version für Package C durchführen. In diesem Fall wird keine Warnung ausgelöst.
Abhängigkeiten zwischen Cousins
Wenn unterschiedliche Paketversionen in verschiedenen Untergraphen im Diagramm aus der Anwendung referenziert werden, verwendet NuGet die niedrigste Version, die alle Versionsanforderungen erfüllt (wie bei der niedrigsten anwendbaren Version und unverankerten Versionen Regeln). In der folgenden Abbildung erfüllt Version 2.0.0 von Package B die andere >=1.0.0-Einschränkung und wird daher verwendet:
Beachten Sie, dass sich die Pakete nicht auf dem gleichen Abstand befinden müssen, damit die Regel der Vetternabhängigkeiten angewendet werden kann. Im folgenden Diagramm wird "Package D 2.0.0" im Untergraphen "Paket C" ausgewählt, und "Package D 3.0.0" wird im Unterverzeichnis von Paket A ausgewählt. Im Unterdiagramm "Anwendung" gibt es keine direkte Abhängigkeit von Package D, sodass die niedrigste anwendbare Version Regel angewendet wird und Version 3.0.0 ausgewählt wird.
In einigen Fällen ist es nicht möglich, alle Versionsanforderungen zu erfüllen. Wie unten dargestellt, erfordert Package A genau Package B 1.0.0 und Package C Package B >=2.0.0, dann kann NuGet die Abhängigkeiten nicht beheben und gibt einen Fehler.
In diesen Fällen sollte der Consumer der obersten Ebene (die Anwendung oder das Paket) eine eigene direkte Abhängigkeit von Paket B hinzufügen, sodass die Regel der direkten Abhängigkeit siegt.
Versionsbereiche und Vorabversionen mit PackageReference
Es ist nicht ungewöhnlich, dass von einem Paket sowohl stabile als auch Vorabversionen verfügbar sind.
Beim Auflösen eines Abhängigkeitsdiagramms entscheidet NuGet, ob Vorabversionen für ein Paket basierend auf einer einzigen Regel berücksichtigt werden sollen: If the project or any packages within the graph request a prerelease version of a package, then include both prerelease or stable versions, otherwise consider stable versions only.
In der Praxis bedeutet dies unter der niedrigsten anwendbaren Regel Folgendes:
Versionsbereich | Verfügbare Versionen | Ausgewählte Version |
---|---|---|
[1.0.0, 2.0.0) | 1.2.0-beta.1, 1.2.0, | 1.2.0 |
[1.0.0, 2.0.0-0) | 1.2.0-beta.1, 1.2.0, | 1.2.0-beta.1 |
[1.0.0, 2.0.0) | 1.2.0-beta.1, 2.0.0-beta.3 | Keine, NU1103 wird ausgelöst. |
[1.0.0, 2.0.0-rc) | 1.2.0-beta.1, 2.0.0-beta.3 | 1.2.0-beta.1 |
Abhängigkeitsauflösung mit packages.config
Mit packages.config
werden die Abhängigkeiten eines Projekts als flache Liste in packages.config
geschrieben. Alle Abhängigkeiten dieser Pakete werden auch in derselben Liste geschrieben. Wenn Pakete installiert sind, ändert NuGet möglicherweise auch die .csproj
Datei, app.config
, web.config
und andere einzelne Dateien.
Mit packages.config
versucht NuGet, Abhängigkeitskonflikte während der Installation jedes einzelnen Pakets zu beheben. Wenn "Package A" installiert wird und von "Package B" abhängt und "Package B" bereits in packages.config
als Abhängigkeit von etwas anderem aufgeführt ist, vergleicht NuGet die angeforderten Versionen von Package B und versucht, eine Version zu finden, die alle Versionsbeschränkungen erfüllt. Insbesondere wählt NuGet die untere major.minor Version aus, die Abhängigkeiten erfüllt.
Standardmäßig sucht NuGet 2.8 nach der niedrigsten Patchversion (siehe NuGet 2.8 Versionshinweise). Sie können diese Einstellung über das Attribut DependencyVersion
in NuGet.Config
sowie den Schalter -DependencyVersion
in der Befehlszeile steuern.
Der packages.config
Prozess zum Auflösen von Abhängigkeiten wird für größere Abhängigkeitsdiagramme kompliziert. Jede neue Paketinstallation erfordert eine Durchquerung des gesamten Diagramms und erhöht die Wahrscheinlichkeit für Versionskonflikte. Wenn ein Konflikt auftritt, wird die Installation beendet, wobei das Projekt in einem unbestimmten Zustand bleibt, insbesondere bei potenziellen Änderungen an der Projektdatei selbst. Dies ist kein Problem beim Verwenden anderer Paketverwaltungsformate.
Versionsbereiche und Vorabversionen mit packages.config
packages.config Auflösung erlaubt keine Vermischung von stabilen und vorab freigegebenen Abhängigkeiten in einem Graph.
Wenn eine Abhängigkeit mit einem Bereich wie [1.0.0, 2.0.0)
ausgedrückt wird, sind Vorabversionspakete im Diagramm nicht zulässig.
Verwalten von Abhängigkeitsressourcen
Wenn Sie das PackageReference-Format verwenden, können Sie steuern, welche Ressourcen aus Abhängigkeiten in das Projekt der obersten Ebene fließen. Ausführliche Informationen finden Sie in PackageReference.
Wenn das Projekt der obersten Ebene selbst ein Paket ist, haben Sie auch die Kontrolle über diesen Fluss, indem Sie die include
und exclude
Attribute mit Abhängigkeiten verwenden, die in der .nuspec
Datei aufgeführt sind. Siehe .nuspec-Referenz - Abhängigkeiten.
Ausschließen von Referenzen
Es gibt Szenarien, in denen Assemblys mit demselben Namen in einem Projekt mehrmals referenziert werden können, wodurch Entwurfszeit- und Buildzeitfehler erzeugt werden. Betrachten Sie ein Projekt, das eine benutzerdefinierte Version von C.dll
enthält, und verweist auf Package C, das auch C.dll
enthält. Gleichzeitig hängt das Projekt auch von Package B ab, das auch von Package C und C.dll
abhängt. Daher kann NuGet nicht bestimmen, welche C.dll
verwendet werden sollen. Sie können jedoch nicht nur die Abhängigkeit des Projekts von Paket C entfernen, da Paket B ebenfalls davon abhängt.
Um dies zu beheben, müssen Sie direkt auf die gewünschte C.dll
verweisen (oder ein anderes Paket verwenden, das auf die richtige verweist), und dann eine Abhängigkeit von Package C hinzufügen, die alle zugehörigen Ressourcen ausschließt. Dies erfolgt wie folgt, je nach verwendeter Paketverwaltungsformat:
PackageReference-: Fügen Sie
ExcludeAssets="All"
in die Abhängigkeit hinzu.<PackageReference Include="PackageC" Version="1.0.0" ExcludeAssets="All" />
packages.config
: Entfernen Sie den Verweis auf PackageC aus der.csproj
Datei, sodass nur auf die gewünschte Version vonC.dll
verwiesen wird.
Abhängigkeitsupdates während der Paketinstallation
Wenn eine Abhängigkeitsversion bereits erfüllt ist, wird die Abhängigkeit während anderer Paketinstallationen nicht aktualisiert. Ziehen Sie beispielsweise das Paket A in Betracht, das von Paket B abhängt, und gibt 1.0 für die Versionsnummer an. Das Quell-Repository enthält Die Versionen 1.0, 1.1 und 1.2 des Pakets B. Wenn A in einem Projekt installiert ist, das bereits B Version 1.0 enthält, wird B 1.0 weiterhin verwendet, da sie die Versionseinschränkung erfüllt. Wenn paket A jedoch Version 1.1 oder höher von B anfordert, wird B 1.2 installiert.
Beheben von inkompatiblen Paketfehlern
Während eines Paketwiederherstellungsvorgangs wird möglicherweise der Fehler "Mindestens ein Paket ist nicht kompatibel..." angezeigt. oder dass ein Paket mit dem Zielframework des Projekts "nicht kompatibel" ist.
Dieser Fehler tritt auf, wenn mindestens eines der Pakete, auf die in Ihrem Projekt verwiesen wird, nicht darauf hinweist, dass sie das Zielframework des Projekts unterstützen. d. h., das Paket enthält keine geeignete DLL in seinem lib
Ordner für ein Zielframework, das mit dem Projekt kompatibel ist. (Eine Liste finden Sie unter Ziel-Frameworks.)
Wenn ein Projekt z. B. auf netstandard1.6
ausgerichtet ist und Sie versuchen, ein Paket zu installieren, das DLLs nur in den Ordnern lib\net20
und \lib\net45
enthält, werden Meldungen wie die folgenden für das Paket und möglicherweise seine Nachfolger angezeigt:
Restoring packages for myproject.csproj...
Package ContosoUtilities 2.1.2.3 is not compatible with netstandard1.6 (.NETStandard,Version=v1.6). Package ContosoUtilities 2.1.2.3 supports:
- net20 (.NETFramework,Version=v2.0)
- net45 (.NETFramework,Version=v4.5)
Package ContosoCore 0.86.0 is not compatible with netstandard1.6 (.NETStandard,Version=v1.6). Package ContosoCore 0.86.0 supports:
- 11 (11,Version=v0.0)
- net20 (.NETFramework,Version=v2.0)
- sl3 (Silverlight,Version=v3.0)
- sl4 (Silverlight,Version=v4.0)
One or more packages are incompatible with .NETStandard,Version=v1.6.
Package restore failed. Rolling back package changes for 'MyProject'.
Führen Sie eine der folgenden Aktionen aus, um Inkompatibilitäten zu beheben:
- Richten Sie Ihr Projekt auf ein Framework aus, das von den Paketen unterstützt wird, die Sie verwenden möchten.
- Wenden Sie sich an den Autor der Pakete, und arbeiten Sie mit ihnen zusammen, um Unterstützung für Ihr ausgewähltes Framework hinzuzufügen. Jede Paketauflistungsseite auf nuget.org verfügt zu diesem Zweck über einen Link Kontaktieren Sie die Eigentümer.
Trinkgeld
Alternative Lösung: NuGetSolver ist eine von Microsoft DevLabs entwickelte Visual Studio-Erweiterung, die zur Lösung von Abhängigkeitskonflikten entwickelt wurde. Es automatisiert den Prozess der Identifizierung und Behebung dieser Probleme. Weitere Details finden Sie auf der Seite NuGetSolver auf dem Visual Studio Marketplace, und wir freuen uns, Ihr Feedback zu Ihrer Erfahrung zu hören.