Jak narzędzie NuGet rozwiązuje zależności pakietów
Za każdym razem, gdy pakiet jest instalowany lub instalowany ponownie, w tym instalowany w ramach procesu przywracania , NuGet instaluje również wszelkie dodatkowe pakiety, od których zależy ten pierwszy pakiet.
Te bezpośrednie zależności mogą mieć również zależności samodzielnie, które mogą nadal mieć dowolną głębokość. Spowoduje to utworzenie wykresu zależności opisujące relacje między pakietami na wszystkich poziomach.
Jeśli wiele pakietów ma tę samą zależność, ten sam identyfikator pakietu może pojawić się w grafie wiele razy, potencjalnie z różnymi ograniczeniami wersji. Jednak tylko jedna wersja danego pakietu może być używana w projekcie, więc NuGet musi wybrać, która wersja jest używana. Dokładny proces zależy od używanego formatu zarządzania pakietami.
Rozwiązywanie zależności za pomocą funkcji PackageReference
Podczas instalowania pakietów w projektach przy użyciu formatu PackageReference NuGet dodaje odwołania do prostego grafu pakietów w odpowiednim pliku i rozwiązuje konflikty z wyprzedzeniem. Ten proces jest określany jako przywracanie przejściowe. Ponowne instalowanie lub przywracanie pakietów jest następnie procesem pobierania pakietów wymienionych na wykresie, co powoduje szybsze i bardziej przewidywalne kompilacje.
Możesz również skorzystać z wersji zmiennoprzecinkowych, takich jak 2.8.*, aby uniknąć modyfikowania projektu w celu korzystania z najnowszej wersji pakietu. W przypadku korzystania z wersji zmiennych zalecamy włączenie funkcji blokady pliku w celu zapewnienia powtarzalności.
Gdy proces przywracania NuGet jest uruchamiany przed kompilacją, najpierw rozpoznaje zależności w pamięci, a następnie zapisuje wynikowy graf do pliku o nazwie project.assets.json
.
Plik zasobów znajduje się w lokalizacji MSBuildProjectExtensionsPath
, która jest domyślnie ustawiona na folder "obj" projektu.
Program MSBuild odczytuje ten plik i tłumaczy go na zestaw folderów, w których można znaleźć potencjalne odwołania, a następnie dodaje je do drzewa projektu w pamięci.
Plik project.assets.json
jest tymczasowy i nie należy go dodawać do kontroli źródła. Jest on domyślnie wyświetlany zarówno w .gitignore
, jak i .tfignore
. Zobacz Pakiety i kontrola źródła.
Reguły rozwiązywania zależności
Przywracanie przejściowe stosuje cztery główne reguły rozwiązywania zależności: najniższa odpowiednia wersja, wersje zmienne, wygrywa zależność bezpośredniai zależności pokrewne .
Najniższa odpowiednia wersja
Najniższa odpowiednia reguła wersji przywraca najniższą możliwą wersję pakietu zgodnie z jego zależnościami. Dotyczy to również zależności aplikacji lub biblioteki klas, chyba że zadeklarowane jako zmiennoprzecinkowe.
Na poniższym rysunku, na przykład wersja 1.0-beta jest uznawana za niższą niż 1.0, więc NuGet wybiera wersję 1.0:
Na następnym rysunku wersja 2.1 nie jest dostępna w źródle, ale ponieważ warunek wersji to >= 2.1, NuGet wybiera następną najniższą wersję, jaka jest dostępna, w tym przypadku 2.2.
kanale
Gdy aplikacja określa dokładny numer wersji, taki jak 1.2, który nie jest dostępny w źródle, NuGet zgłasza błąd podczas próby zainstalowania lub przywrócenia pakietu.
Wersje elastyczne
Zmienna wersja zależności jest określona z znakiem * . Na przykład 6.0.*
. Ta specyfikacja wersji mówi "użyj najnowszej wersji 6.0.x"; 4.*
oznacza "używanie najnowszej wersji 4.x". Użycie wersji zmiennoprzecinkowej zmniejsza zmiany w pliku projektu, zachowując jednocześnie aktualność najnowszej wersji zależności.
Wersje zmiennoprzecinkowe można określić tylko na poziomie projektu.
W przypadku korzystania z wersji przestawnej program NuGet rozpoznaje najwyższą wersję pakietu zgodnego ze wzorcem wersji, na przykład 6.0.*
pobiera najwyższą wersję pakietu rozpoczynającego się od wersji 6.0:
Wersja | Wersje obecne na serwerze | Rezolucja | Powód | Notatki |
---|---|---|---|---|
* | 1.1.0 1.1.1 1.2.0 1.3.0-alpha |
1.2.0 | Najwyższa stabilna wersja. | |
1.1.* | 1.1.0 1.1.1 1.1.2-alfa 1.2.0-alfa |
1.1.1 | Najwyższa stabilna wersja, która uwzględnia określony wzorzec. | |
*-* | 1.1.0 1.1.1 1.1.2-alfa 1.3.0-beta |
1.3.0-beta | Najwyższa wersja, w tym nie stabilne wersje. | Dostępne w programie Visual Studio w wersji 16.6, NuGet w wersji 5.6, zestawu .NET Core SDK w wersji 3.1.300 |
1.1.*-* | 1.1.0 1.1.1 1.1.2-alfa 1.1.2-beta 1.3.0-beta |
1.1.2-beta | Najwyższa wersja zgodna z wzorcem i włącznie z niestabilnymi wersjami. | Dostępne w programie Visual Studio w wersji 16.6, NuGet w wersji 5.6, zestawu .NET Core SDK w wersji 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 | Pomimo tego, że jest to zakres wersji z częścią wstępną, stabilne wersje są dozwolone, jeśli odpowiadają stabilnej części. Biorąc pod uwagę, wybrano wersję 1.2.0 > 1.2.0-rc.2. |
Notatka
Rozpoznawanie wersji zmiennoprzecinkowych nie uwzględnia tego, czy na liście znajduje się pakiet. Rozwiązanie wersji pływających nastąpi lokalnie, jeśli warunki mogą być spełnione z pakietami w Folderze Globalnych Pakietów.
Bezpośrednia zależność zwycięża
Gdy graf pakietu dla aplikacji zawiera różne wersje pakietu w tej samej podgrafie, a jedna z tych wersji jest bezpośrednią zależnością w tym podgrafie, ta wersja zostanie wybrana dla tej podgrafu, a reszta zostanie zignorowana. To zachowanie umożliwia aplikacji zastąpienie dowolnej konkretnej wersji pakietu na grafie zależności.
W poniższym przykładzie aplikacja zależy bezpośrednio od pakietu B z ograniczeniem wersji >=2.0.0. Aplikacja zależy również od pakietu A, który z kolei zależy od pakietu B, ale z ograniczeniem >=1.0.0. Ponieważ zależność od pakietu B 2.0.0 jest bezpośrednią zależnością od aplikacji na grafie, używana jest ta wersja:
Ostrzeżenie
Reguła wygranych bezpośrednich zależności może spowodować obniżenie wersji pakietu, co może zakłócić inne zależności w grafie. Po obniżeniu poziomu pakietu NuGet dodaje ostrzeżenie , aby ostrzec użytkownika.
Ta reguła powoduje również większą wydajność z dużym wykresem zależności. Gdy bliższa zależność w tej samej podgrafie ma wyższą wersję niż dalszą, program NuGet ignoruje tę zależność, a program NuGet ignoruje również wszystkie pozostałe zależności od tej gałęzi grafu.
Na poniższym diagramie, na przykład, ponieważ jest używany pakiet C 2.0.0, NuGet ignoruje wszystkie gałęzie w tym podgrafie, które odwołują się do wcześniejszej wersji pakietu C:
Za pomocą tej reguły nuGet próbuje uhonorować intencję autora pakietu. Na poniższym diagramie autor pakietu A jawnie obniżył pakiet C 1.0.0 z pakietu C 2.0.0.
Właściciel aplikacji może zdecydować się na uaktualnienie pakietu C do wersji nowszej niż 2.0.0, co nie powoduje dalszego obniżania wersji pakietu C. W takim przypadku nie zostanie zgłoszone żadne ostrzeżenie.
Zależności kuzyna
Gdy różne wersje pakietów są określane w różnych podgrafach na grafie z aplikacji, NuGet używa najniższej wersji, która spełnia wszystkie wymagania dotyczące wersji (podobnie jak w przypadku najniższej pasującej wersji i wersji zmiennych reguł). Na poniższej ilustracji na przykład wersja 2.0.0 pakietu B spełnia pozostałe >=1.0.0 ograniczenia i dlatego jest używany:
Należy pamiętać, że pakiety nie muszą znajdować się na tej samej odległości, aby reguła zależności kuzyna miała zastosowanie. Na poniższym diagramie pakiet D 2.0.0 jest wybierany w podgrafie Package C, a pakiet D 3.0.0 jest wybierany w podgrafie Pakietu A. W podgrafie Aplikacja nie ma bezpośredniej zależności od pakietu D, dlatego jest stosowana reguła najniższej odpowiedniej wersji i jest wybrana wersja 3.0.0.
W niektórych przypadkach nie można spełnić wszystkich wymagań dotyczących wersji. Jak pokazano poniżej, jeśli pakiet A wymaga dokładnie pakietu B 1.0.0 i pakietu C wymaga pakietu B >=2.0.0, nuGet nie może rozpoznać zależności i daje błąd.
W takich sytuacjach odbiorca najwyższego poziomu (aplikacja lub pakiet) powinien dodać własną bezpośrednią zależność od pakietu B, aby zależność Bezpośrednia wygrywała regułę.
Zakresy wersji i wersje wstępne z funkcją PackageReference
Nie jest niczym niezwykłym, że pakiet ma dostępne wersje stabilne i wstępne.
Podczas rozpoznawania grafu zależności nuGet decyduje, czy rozważyć wersje wstępne pakietu na podstawie jednej reguły: 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.
W praktyce, zgodnie z najniższą obowiązującą regułą, oznacza to:
Zakres wersji | Dostępne wersje | Wybrana wersja |
---|---|---|
[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 | Brak, NU1103 jest wywoływana. |
[1.0.0, 2.0.0-rc) | 1.2.0-beta.1, 2.0.0-beta.3 | 1.2.0-beta.1 |
Rozwiązywanie zależności za pomocą packages.config
W przypadku packages.config
zależności projektu są zapisywane w packages.config
jako płaska lista. Wszystkie zależności tych pakietów są również zapisywane na tej samej liście. Po zainstalowaniu pakietów pakiet NuGet może również zmodyfikować plik .csproj
, app.config
, web.config
i inne pojedyncze pliki.
W przypadku packages.config
program NuGet próbuje rozwiązać konflikty zależności podczas instalacji każdego pojedynczego pakietu. Oznacza to, że jeśli pakiet A jest instalowany i zależy od pakietu B, a pakiet B jest już wymieniony w packages.config
jako zależność czegoś innego, NuGet porównuje wersje żądanego pakietu B i próbuje znaleźć wersję spełniającą wszystkie ograniczenia wersji. W szczególności NuGet wybiera niższą wersję główną.pomocniczą , która spełnia zależności.
Domyślnie pakiet NuGet 2.8 szuka najniższej wersji poprawki (zobacz informacje o wersji NuGet 2.8). To ustawienie można kontrolować za pomocą atrybutu DependencyVersion
w NuGet.Config
i przełącznika -DependencyVersion
w wierszu polecenia.
Proces packages.config
rozwiązywania zależności jest skomplikowany w przypadku większych grafów zależności. Każda nowa instalacja pakietu wymaga przeanalizowania całego grafu, co zwiększa ryzyko konfliktów wersji. Gdy wystąpi konflikt, instalacja zostanie zatrzymana, pozostawiając projekt w stanie nieokreślonym, zwłaszcza z potencjalnymi modyfikacjami samego pliku projektu. Nie jest to problem podczas korzystania z innych formatów zarządzania pakietami.
Zakresy wersji i wersje wstępne z packages.config
packages.config rozdzielczość nie zezwala na mieszanie stabilnych i wstępnych zależności w wykresie.
Jeśli zależność wyraża się zakresem, na przykład [1.0.0, 2.0.0)
, przedpremierowe pakiety nie są dozwolone w grafie.
Zarządzanie zasobami zależności
W przypadku korzystania z formatu PackageReference można kontrolować, które zasoby z zależności przepływają do projektu najwyższego poziomu. Aby uzyskać szczegółowe informacje, zobacz PackageReference.
Gdy projekt najwyższego poziomu jest pakietem, masz również kontrolę nad tym przepływem przy użyciu atrybutów include
i exclude
z zależnościami wymienionymi w pliku .nuspec
. Zobacz .nuspec odnośnik - zależności.
Wykluczanie odwołań
Istnieją scenariusze, w których zestawy o tej samej nazwie mogą być przywoływały więcej niż raz w projekcie, tworząc błędy czasu projektowania i czasu kompilacji. Rozważmy projekt zawierający niestandardową wersję C.dll
i odwołuje się do pakietu C, który zawiera również C.dll
. Jednocześnie projekt zależy również od pakietu B, który również zależy od pakietu C i C.dll
. W związku z tym pakiet NuGet nie może określić, który C.dll
użyć, ale nie można po prostu usunąć zależności projektu od pakietu C, ponieważ pakiet B również od niego zależy.
Aby rozwiązać ten problem, musisz bezpośrednio odwołać się do żądanego C.dll
(lub użyć innego pakietu odwołującego się do odpowiedniego), a następnie dodać zależność od pakietu C, która wyklucza wszystkie jego zasoby. Odbywa się to w następujący sposób w zależności od używanego formatu zarządzania pakietami:
PackageReference: dodaj
ExcludeAssets="All"
w definicji zależności:<PackageReference Include="PackageC" Version="1.0.0" ExcludeAssets="All" />
packages.config
: usuń odwołanie do packageC z pliku.csproj
, aby odwoływać się tylko do żądanej wersjiC.dll
.
Aktualizacje zależności podczas instalowania pakietu
Jeśli wersja zależności jest już spełniona, zależność nie jest aktualizowana podczas innych instalacji pakietów. Rozważmy na przykład pakiet A, który zależy od pakietu B i określa numer wersji 1.0. Repozytorium źródłowe zawiera wersje 1.0, 1.1 i 1.2 pakietu B. Jeśli element A jest zainstalowany w projekcie, który zawiera już wersję B 1.0, usługa B 1.0 pozostaje w użyciu, ponieważ spełnia ograniczenie wersji. Jednak jeśli pakiet A wymagałby wersji 1.1 lub nowszej pakietu B, zainstalowany zostałby B 1.2.
Rozwiązywanie problemów z niezgodnymi błędami pakietu
Podczas operacji przywracania pakietu może zostać wyświetlony błąd "Co najmniej jeden pakiet nie jest zgodny..." lub że pakiet "nie jest zgodny" z platformą docelową projektu.
Ten błąd występuje, gdy co najmniej jeden pakiet, do którego odwołuje się projekt, nie wskazuje na to, że obsługują strukturę docelową projektu; oznacza to, że pakiet nie zawiera odpowiedniej biblioteki DLL w folderze lib
dla platformy docelowej zgodnej z projektem. (Zobacz Platformy docelowe dla listy).
Jeśli na przykład projekt jest przeznaczony dla netstandard1.6
i próbujesz zainstalować pakiet zawierający biblioteki DLL tylko w folderach lib\net20
i \lib\net45
, zostaną wyświetlone komunikaty podobne do następujących dla pakietu i prawdopodobnie jego zależności:
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'.
Aby rozwiązać problemy z niezgodnościami, wykonaj jedną z następujących czynności:
- Dostosuj projekt do platformy, która jest obsługiwana przez pakiety, które chcesz używać.
- Skontaktuj się z autorem pakietów i współpracuj z nim, aby dodać obsługę wybranego frameworku. Każda strona listująca pakiety na nuget.org ma w tym celu link Kontakt z właścicielami.
Napiwek
Rozwiązanie alternatywne: NuGetSolver to rozszerzenie programu Visual Studio opracowane przez firmę Microsoft DevLabs, które pomaga w rozwiązywaniu konfliktów zależności. Automatyzuje proces identyfikowania i rozwiązywania tych problemów. Aby uzyskać więcej informacji, odwiedź stronę NuGetSolver w witrynie Visual Studio Marketplace. Będziemy wdzięczni za Twoją opinię na temat Twoich doświadczeń.