Jak NuGet řeší závislosti balíčků
Kdykoli se balíček nainstaluje nebo přeinstaluje, což zahrnuje instalaci v rámci procesu obnovení, NuGet také nainstaluje všechny další balíčky, na kterých závisí tento první balíček.
Tyto okamžité závislosti pak mohou mít také své vlastní závislosti, což může pokračovat do libovolné hloubky. To vytvoří graf závislostí , který popisuje vztahy mezi balíčky na všech úrovních.
Pokud má více balíčků stejnou závislost, může se stejné ID balíčku v grafu objevit vícekrát, potenciálně s různými omezeními verze. V projektu se ale dá použít jenom jedna verze daného balíčku, takže NuGet musí zvolit, která verze se použije. Přesný proces závisí na použitém formátu správy balíčků.
Řešení závislostí pomocí PackageReference
Při instalaci balíčků do projektů pomocí formátu PackageReference přidá NuGet odkazy na plochý graf balíčků v příslušném souboru a předem vyřeší konflikty. Tento proces se označuje jako tranzitivní obnovení. Přeinstalace nebo obnovení balíčků je pak proces stažení balíčků uvedených v grafu, což vede k rychlejším a předvídatelnějším sestavením.
Můžete také využít plovoucí verze, například 2.8.*, abyste zabránili úpravám projektu tak, aby používal nejnovější verzi balíčku. Při použití plovoucích verzí doporučujeme povolit funkci uzamknout soubor, aby se zajistila opakovatelnost.
Když se proces obnovení NuGet spustí před sestavením, vyřeší nejprve závislosti v paměti a potom zapíše výsledný graf do souboru s názvem project.assets.json
.
Soubor assets se nachází v MSBuildProjectExtensionsPath
, který ve výchozím nastavení odkazuje na složku obj projektu.
Nástroj MSBuild pak tento soubor přečte a přeloží ho do sady složek, kde lze najít potenciální odkazy, a pak je přidá do stromu projektu v paměti.
Soubor project.assets.json
je dočasný a neměl by být přidán do správy zdrojového kódu. Ve výchozím nastavení je uvedený v .gitignore
i v .tfignore
. Viz Balíčky aspráva zdrojového kódu.
Pravidla řešení závislostí
Přechodné obnovení používá čtyři hlavní pravidla pro řešení závislostí: nejnižší použitelné verze, plovoucí verze, vítězství přímé závislostia příbuzné závislosti.
Nejnižší použitelná verze
Nejnižší použitelné pravidlo verze obnoví nejnižší možnou verzi balíčku, jak je definováno jeho závislostmi. Platí také pro závislosti na aplikaci nebo knihovně tříd, pokud nejsou deklarovány jako plovoucí.
Na následujícím obrázku se například verze 1.0-beta považuje za nižší než 1.0, takže NuGet zvolí verzi 1.0:
Na následujícím obrázku není v kanálu dostupná verze 2.1, ale protože omezení verze je >= 2.1, NuGet vybere další nejnižší verzi, kterou může najít, v tomto případě 2.2.
Pokud aplikace určuje přesné číslo verze, například 1.2, které není dostupné v informačním kanálu, NuGet selže s chybou při pokusu o instalaci nebo obnovení balíčku:
Plovoucí verze
Verze s plovoucí závislostí je určena znakem *. Například 6.0.*
. Tato specifikace verze říká"použití nejnovější verze 6.0.x"; 4.*
znamená"použití nejnovější verze 4.x". Použití plovoucí verze snižuje změny v souboru projektu a současně udržuje aktuální nejnovější verzi závislosti.
Plovoucí verze lze zadat pouze na úrovni projektu.
Při použití plovoucí verze NuGet vyřeší nejvyšší verzi balíčku, která odpovídá vzoru verze, například 6.0.*
získá nejvyšší verzi balíčku, která začíná na verzi 6.0:
Verze | Verze přítomné na serveru | Usnesení | Důvod | Poznámky |
---|---|---|---|---|
* | 1.1.0 1.1.1 1.2.0 1.3.0-alpha |
1.2.0 | Nejvyšší stabilní verze. | |
1.1.* | 1.1.0 1.1.1 1.1.2-alfa 1.2.0-alpha |
1.1.1 | Nejvyšší stabilní verze, která respektuje zadaný vzor. | |
*-* | 1.1.0 1.1.1 1.1.2-alfa 1.3.0-beta |
1.3.0-beta | Nejvyšší verze, včetně nestabilní verze. | K dispozici v sadě Visual Studio verze 16.6, NuGet verze 5.6, .NET Core SDK verze 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 | Nejvyšší verze, která respektuje vzor a zahrnuje nestabilní verze. | Dostupné v sadě Visual Studio ve verzi 16.6, NuGet ve verzi 5.6, .NET Core SDK ve verzi 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 | Navzdory tomu, že jde o rozsah verzí s předběžnou částí, jsou stabilní verze povoleny, pokud se shodují se stabilní částí. Vzhledem k tomu, že 1.2.0 > 1.2.0-rc.2, je zvolen. |
Poznámka
Plovoucí rozlišení verze nebere v úvahu, jestli je uveden balíček nebo ne. Řešení pohyblivých verzí bude provedeno na místní úrovni, pokud podmínky mohou být splněny pomocí balíčků ve složce globálního balíčku.
Přímá závislost vyhrává
Pokud graf balíčků pro aplikaci obsahuje různé verze balíčku ve stejném podgrafu a jedna z těchto verzí je přímá závislost v tomto podgrafu, bude tato verze zvolena pro tento podgraf a zbytek bude ignorován. Toto chování umožňuje aplikaci přepsat jakoukoli konkrétní verzi balíčku v grafu závislostí.
V následujícím příkladu aplikace závisí přímo na balíčku B s omezením verze >=2.0.0. Aplikace také závisí na balíčku A, který zase závisí na balíčku B, ale s omezením >=1.0.0. Vzhledem k tomu, že závislost na balíčku B 2.0.0 je přímá závislost na aplikaci v grafu, používá se tato verze:
Varování
Pravidlo výhry přímé závislosti může vést k downgradu verze balíčku, čímž by mohlo dojít k narušení jiných závislostí v grafu. Když je balíček downgradován, NuGet přidá upozornění , aby uživatele upozornil.
Výsledkem tohoto pravidla je také větší efektivita s velkým grafem závislostí. Pokud má užší závislost ve stejném podgrafu vyšší verzi než další, NuGet tuto závislost ignoruje a NuGet také ignoruje všechny zbývající závislosti na dané větvi grafu.
Například v následujícím diagramu, protože balíček C 2.0.0 se používá, NuGet ignoruje všechny větve v tomto podgrafu, které odkazují na starší verzi balíčku C:
Prostřednictvím tohoto pravidla se NuGet pokusí respektovat záměr autora balíčku. V následujícím diagramu autor balíčku A explicitně downgradoval na Balíček C 1.0.0 z balíčku C 2.0.0.
Vlastník aplikace se může rozhodnout, že balíček C upgraduje na verzi vyšší než 2.0.0, takže verzi balíčku C nebude dále downgradovat. V tomto případě se nevyvolá žádné upozornění.
Závislosti bratrance
Pokud se různé verze balíčků označují v různých podgrafech v grafu z aplikace, NuGet používá nejnižší verzi, která splňuje všechny požadavky na verzi (stejně jako u nejnižší použitelné verze a plovoucí verze pravidla). Na následujícím obrázku, například verze 2.0.0 balíčku B splňuje ostatní >=1.0.0 omezení, a proto se používá:
Mějte na paměti, že balíčky nemusí být na stejné vzdálenosti, aby pravidlo závislostí bratrance bylo možné použít. V následujícím diagramu je balíček D 2.0.0 vybrán v podgrafu Balíček C a balíček D 3.0.0 je vybrán v podgrafu balíčku A. V podgrafu Aplikace neexistuje přímá závislost na balíčku D, takže se použije pravidlo nejnižší použitelné verze a zvolí se verze 3.0.0.
V některých případech není možné splnit všechny požadavky na verzi. Jak je znázorněno níže, pokud balíček A vyžaduje přesně balíček B 1.0.0 a balíček C vyžaduje balíček B >=2.0.0, NuGet nemůže vyřešit závislosti a zobrazí chybu.
V těchto situacích by měl příjemce nejvyšší úrovně (aplikace nebo balíček) přidat vlastní přímou závislost na balíčku B, aby přímá závislost vyhrála pravidlo.
Rozsahy verzí a předběžné verze pomocí PackageReference
Není neobvyklé, že balíček bude mít k dispozici stabilní i předběžné verze.
Při řešení grafu závislostí se NuGet rozhodne, jestli se má zvážit předběžné verze balíčku na základě jednoho pravidla: 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.
V praxi platí, že v rámci nejnižšího platného pravidla to znamená:
Rozsah verzí | Dostupné verze | Vybraná verze |
---|---|---|
[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 | Žádné, NU1103 je vyvolána. |
[1.0.0, 2.0.0-rc) | 1.2.0-beta.1, 2.0.0-beta.3 | 1.2.0-beta.1 |
Řešení závislostí s packages.config
S packages.config
se závislosti projektu zapisují do packages.config
jako plochý seznam. Všechny závislosti těchto balíčků se také zapisují do stejného seznamu. Při instalaci balíčků může NuGet také upravit soubor .csproj
, app.config
, web.config
a další jednotlivé soubory.
Při packages.config
se NuGet pokusí vyřešit konflikty závislostí během instalace jednotlivých balíčků. To znamená, že pokud je balíček A nainstalovaný a závisí na balíčku B a balíček B je již uveden v packages.config
jako závislost něčeho jiného, NuGet porovná požadované verze balíčku B a pokusí se najít verzi, která splňuje všechna omezení verze. NuGet konkrétně vybere nižší verzi major.minor, která splňuje závislosti.
Ve výchozím nastavení NuGet 2.8 hledá nejnižší verzi opravy (viz poznámky k verzi NuGet 2.8). Toto nastavení můžete řídit prostřednictvím atributu DependencyVersion
v NuGet.Config
a přepínačem -DependencyVersion
na příkazovém řádku.
Proces packages.config
pro řešení závislostí se pro větší grafy závislostí zkomplikuje. Každá nová instalace balíčku vyžaduje procházení celého grafu a zvyšuje šanci na konflikty verzí. Když dojde ke konfliktu, instalace se zastaví a projekt zůstane v neurčitém stavu, zvláště při potenciálních úpravách samotného souboru projektu. Nejedná se o problém při použití jiných formátů správy balíčků.
Rozsahy verzí a předběžné verze s packages.config
packages.config rozlišení neumožňuje míchání stabilních a předběžných závislostí v grafu.
Pokud je závislost vyjádřena s rozsahem, jako je [1.0.0, 2.0.0)
, nejsou v grafu povolené předběžné balíčky.
Správa majetků závislostí
Při použití formátu PackageReference můžete řídit, které prostředky ze závislostí proudí do projektu nejvyšší úrovně. Podrobnosti najdete v části PackageReference.
Pokud je projekt nejvyšší úrovně samotným balíčkem, máte také kontrolu nad tímto tokem pomocí include
a exclude
atributů se závislostmi uvedenými v souboru .nuspec
. Viz referenci .nuspec: Závislosti.
Vyloučení odkazů
Existují scénáře, ve kterých sestavení se stejným názvem můžou být v projektu odkazována více než jednou, což vytváří chyby v době návrhu a času sestavení. Zvažte projekt, který obsahuje vlastní verzi C.dll
a odkazuje na balíček C, který obsahuje také C.dll
. Současně projekt také závisí na balíčku B, který také závisí na balíčku C a C.dll
. V důsledku toho NuGet nedokáže určit, který C.dll
použít, ale nemůžete jenom odebrat závislost projektu na balíčku C, protože balíček B na něm také závisí.
Pokud chcete tento problém vyřešit, musíte přímo označit C.dll
, který chcete (nebo použít jiný balíček, který odkazuje na ten správný), a pak přidat závislost na balíčku C, který vylučuje všechny jeho zdroje. To se provádí následovně v závislosti na používaném formátu správy balíčků:
PackageReference: přidejte do závislosti
ExcludeAssets="All"
:<PackageReference Include="PackageC" Version="1.0.0" ExcludeAssets="All" />
packages.config
: Odeberte odkaz na PackageC ze souboru.csproj
, tak, aby odkazoval pouze na požadovanou verziC.dll
.
Aktualizace závislostí během instalace balíčku
Pokud už je verze závislosti splněná, závislost se během jiných instalací balíčků neaktualizuje. Představte si například balíček A, který závisí na balíčku B a určuje číslo verze 1.0. Zdrojové úložiště obsahuje verze 1.0, 1.1 a 1.2 balíčku B. Pokud je v projektu, který již obsahuje B verze 1.0, nainstalováno A, pak B 1.0 zůstává v použití, protože splňuje omezení verze. Pokud však balíček A požaduje verzi 1.1 nebo vyšší verze B, nainstaluje se B 1.2.
Řešení nekompatibilních chyb balíčku
Během operace obnovení balíčku se může zobrazit chyba "Jeden nebo více balíčků není kompatibilní..." nebo že balíček není kompatibilní s cílovou architekturou projektu.
K této chybě dochází, když jeden nebo více balíčků odkazovaných v projektu neznamená, že podporují cílovou architekturu projektu; to znamená, že balíček neobsahuje vhodnou knihovnu DLL ve složce lib
pro cílovou architekturu, která je kompatibilní s projektem. (Seznam najdete v cílových rámců.)
Pokud například projekt cílí na netstandard1.6
a vy se pokusíte nainstalovat balíček, který obsahuje knihovny DLL pouze ve složkách lib\net20
a \lib\net45
, zobrazí se zprávy podobné těmto pro balíček a pravděpodobně i pro jeho závislosti:
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'.
Pokud chcete vyřešit nekompatibilitu, udělejte jednu z těchto věcí:
- Nastavte cílení projektu na architekturu podporovanou balíčky, které chcete použít.
- Obraťte se na autora balíčků a spolupracujte s nimi a přidejte podporu pro vámi zvolenou architekturu. Pro tento účel má každá stránka s výpisem balíčku na nuget.org odkaz Kontaktovat vlastníky.
Spropitné
alternativní řešení: NuGetSolver je rozšíření sady Visual Studio vyvinuté Microsoft DevLabs, které pomáhá řešit konflikty závislostí. Automatizuje proces identifikace a řešení těchto problémů. Další podrobnosti najdete na stránce NuGetSolver na webu Visual Studio Marketplace a rádi si poslechneme váš názor na vaše prostředí.