Hogyan oldja fel a NuGet a csomagfüggőségeket?
Minden alkalommal, amikor egy csomag telepítése vagy újratelepítése történik, beleértve a visszaállítási folyamat részeként történő telepítést is, a NuGet minden további csomagot is telepít, amelyektől az első csomag függ.
Ezek az azonnali függőségek ezután önálló függőségekkel is rendelkezhetnek, amelyek továbbra is tetszőleges mélységig tarthatnak. Ez egy függőségi gráf hoz létre, amely minden szinten leírja a csomagok közötti kapcsolatokat.
Ha több csomag azonos függőséggel rendelkezik, akkor ugyanaz a csomagazonosító többször is megjelenhet a gráfban, esetleg különböző verziókorlátozásokkal. Egy projektben azonban csak egy csomag egy verziója használható, ezért a NuGetnek ki kell választania, hogy melyik verziót használja. A pontos folyamat a használt csomagkezelési formátumtól függ.
Függőségfeloldás a PackageReference használatával
Amikor csomagokat telepít projektekbe a PackageReference formátummal, a NuGet hivatkozásokat ad hozzá egy lapos csomagdiagramhoz a megfelelő fájlban, és idővel feloldja az ütközéseket. Ezt a folyamatot tranzitív visszaállításnakhívják. A csomagok újratelepítése vagy visszaállítása a gráfban felsorolt csomagok letöltésének folyamata, amely gyorsabb és kiszámíthatóbb buildeket eredményez.
Kihasználhatja a lebegő verziókat is, például a 2.8.*-ot, hogy ne módosítsa a projektet a csomag legújabb verziójának használatára. Lebegő verziók használata esetén javasoljuk, hogy engedélyezze a zárolási fájl funkcióit az ismétlődés biztosítása érdekében.
Amikor a NuGet-visszaállítási folyamat a build előtt fut, először a memóriában oldja fel a függőségeket, majd az eredményül kapott gráfot egy project.assets.json
nevű fájlba írja.
Az eszközfájl a MSBuildProjectExtensionsPath
található, amely alapértelmezés szerint a projekt "obj" mappájába kerül.
Az MSBuild ezután felolvassa ezt a fájlt, és lefordítja egy olyan mappába, ahol lehetséges hivatkozások találhatók, majd hozzáadja őket a projektfához a memóriában.
A project.assets.json
fájl ideiglenes, és nem adható hozzá a forrásvezérlőhöz. Alapértelmezés szerint .gitignore
és .tfignore
is szerepel a listán. Lásd: Csomagok és forrásvezérlő.
Függőségfeloldási szabályok
A tranzitív visszaállítás négy fő szabályt alkalmaz a függőségek feloldására: legalacsonyabban alkalmazható verzió, lebegő verzió, közvetlen függőségi, valamint unokatestvér-függőségek.
Legalacsonyabban alkalmazható verzió
A legalacsonyabb alkalmazható verziószabály visszaállítja a csomagnak a függőségei által meghatározott legalacsonyabb lehetséges verzióját. Alkalmazásra vagy osztálykönyvtárra vonatkozó függőségekre is érvényes, kivéve, ha lebegőként van deklarálva .
Az alábbi ábrán például az 1.0-bétaverzió 1.0-nál alacsonyabbnak tekinthető, így a NuGet az 1.0-s verziót választja:
A következő ábrán a 2.1-es verzió nem érhető el a hírcsatornán, de mivel a verziókorlátozás >= 2.1 A NuGet a következő legalacsonyabb verziót választja, ebben az esetben a 2.2-es verziót:
Ha egy alkalmazás pontos verziószámot (például 1.2) ad meg, amely nem érhető el a hírcsatornán, a NuGet hibát jelez a csomag telepítésekor vagy visszaállításakor:
Lebegő verziók
A *karakterrel egy lebegő függőségi verzió van megadva. Például 6.0.*
. Ez a verzióspecifikáció "a legújabb 6.0.x verziót használja"; 4.*
azt jelenti, hogy "használja a legújabb 4.x verziót". A lebegő verzió használata csökkenti a projektfájl módosításait, miközben naprakészen tartja a függőség legújabb verzióját.
A lebegő verziók csak a projekt szintjén adhatók meg.
Lebegő verzió használatakor a NuGet feloldja a csomag azon legmagasabb verzióját, amely megfelel a verziómintának, például 6.0.*
a 6.0-val kezdődő csomag legmagasabb verzióját kapja meg:
Verzió | A kiszolgálón található verziók | Határozat | Ok | Feljegyzések |
---|---|---|---|---|
* | 1.1.0 1.1.1 1.2.0 1.3.0-alfa |
1.2.0 | A legmagasabb stabil verzió. | |
1.1.* | 1.1.0 1.1.1 1.1.2-alfa 1.2.0-alfa |
1.1.1 | A megadott mintát tiszteletben tartó legmagasabb stabil verzió. | |
*-* | 1.1.0 1.1.1 1.1.2-alfa 1.3.0-bétaverzió |
1.3.0-bétaverzió | A legmagasabb verzió, beleértve a nem stabil verziókat is. | Elérhető a Visual Studio 16.6-os, a NuGet 5.6-os és a .NET Core SDK 3.1.300-es verziójában |
1.1.*-* | 1.1.0 1.1.1 1.1.2-alfa 1.1.2-bétaverzió 1.3.0-bétaverzió |
1.1.2-bétaverzió | A mintát tiszteletben tartó legmagasabb verzió, beleértve a nem stabil verziókat is. | Elérhető a Visual Studio 16.6-os, a NuGet 5.6-os és a .NET Core SDK 3.1.300-es verziójában |
1.2.0-rc.* | 1.1.0 1.2.0-rc.1 1.2.0-rc.2 1.2.0 |
1.2.0 | Annak ellenére, hogy ez egy verziótartomány egy előzetes verzió résszel, a stabil verziók engedélyezettek, ha megfelelnek a stabil résznek. Tekintettel arra, hogy 1.2.0 > 1.2.0-rc.2, ezt választották. |
Jegyzet
A lebegő verzió kiválasztása nem veszi figyelembe, hogy egy csomag szerepel-e a listában. A lebegő verziók feloldása helyben lesz elvégezve, ha a feltételeket a Globális Csomagmappában található csomagokkal lehet teljesíteni.
A közvetlen függőség nyer
Ha egy alkalmazás csomaggráfja egy csomag különböző verzióit tartalmazza ugyanabban az algráfban, és az egyik verzió közvetlen függőséget jelent az algráfban, akkor a program ezt a verziót választja ki az algráfhoz, a többit pedig figyelmen kívül hagyja. Ez a viselkedés lehetővé teszi az alkalmazások számára, hogy felülbírálják a függőségi gráf adott csomagverzióját.
Az alábbi példában az alkalmazás közvetlenül a B csomagtól függ, >=2.0.0 verziókorlátozással. Az alkalmazás az A csomagtól is függ, amely viszont a B csomagtól is függ, de >=1.0.0 korlátozással. Mivel a B 2.0.0 csomag függősége közvetlen függőség az alkalmazáshoz a gráfban, ezt a verziót használja a rendszer:
Figyelmeztetés
A "Közvetlen függőség nyer" szabály a csomagverzió leminősítését eredményezhet, ami potenciálisan megszakíthatja a gráf egyéb függőségeit. Ha egy csomag visszaminősítése történik, a NuGet egy figyelmeztetést ad hozzá, amely figyelmezteti a felhasználót.
Ez a szabály nagyobb hatékonyságot is eredményez egy nagy függőségi diagrammal. Ha ugyanabban az algráfban egy közelebbi függőség magasabb verziójú, mint egy másik, akkor a NuGet figyelmen kívül hagyja ezt a függőséget, és a NuGet a gráf ezen ágán lévő összes fennmaradó függőséget is figyelmen kívül hagyja.
Az alábbi ábrán például a C 2.0.0 csomag használata miatt a NuGet figyelmen kívül hagyja az algráf azon ágait, amelyek a C csomag egy korábbi verziójára hivatkoznak:
Ezzel a szabálysal a NuGet megpróbálja tiszteletben tartani a csomag szerzőjének szándékát. Az alábbi ábrán az A csomag szerzője kifejezetten visszalépett a C 2.0.0 verzióról a C 1.0.0 verzióra.
Az alkalmazás tulajdonosa dönthet úgy, hogy a C csomagot a 2.0.0-nál magasabb verzióra frissíti, így a C csomag verziószámának további leminősítése nem történik meg. Ebben az esetben nincs figyelmeztetés.
Unokatestvér-függőségek
Ha a különböző csomagverziókat az alkalmazás gráfjának különböző algráfjaiban hivatkoznak, a NuGet az összes verziókövetelménynek megfelelő legalacsonyabb verziót használja, a legalacsonyabb alkalmazható verzió és a lebegő verzió szabályai szerint. Az alábbi képen például a B csomag 2.0.0-s verziója megfelel a másik >=1.0.0 kényszernek, és így használja:
Vegye figyelembe, hogy a csomagoknak nem kell azonos távolságon lenniük ahhoz, hogy az unokatestvér függőségi szabályt alkalmazzák. Az alábbi ábrán a D 2.0.0 csomag van kiválasztva a C csomag algráfjában, a D 3.0.0 csomag pedig az A csomag algráfjában. Az alkalmazás-algráfban nincs közvetlen függőség a D csomaghoz, ezért a rendszer a legkisebb alkalmazható verziójú szabályt alkalmazza, és a 3.0.0-s verziót választja ki.
Bizonyos esetekben nem lehet megfelelni az összes verziókövetelményeknek. Amint az alább látható, ha az A csomaghoz pontosan b 1.0.0 csomag szükséges, és a C csomaghoz b csomagra van szükség >=2.0.0, akkor a NuGet nem tudja feloldani a függőségeket, és hibát ad.
Ezekben az esetekben a felső szintű felhasználónak (alkalmazásnak vagy csomagnak) hozzá kell adnia saját közvetlen függőségét a B csomaghoz, hogy érvényesüljön a közvetlen függőségre vonatkozó nyerjen szabály.
Verziótartományok és előzetes verziók a PackageReference használatával
Nem szokatlan, hogy egy csomag stabil és előzetes verzióval is rendelkezik.
Függőségi gráf feloldásakor a NuGet eldönti, hogy megfontolja-e a csomagok előzetes verzióit egyetlen szabály alapján: 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.
A gyakorlatban a legalacsonyabb érvényes szabály szerint ez a következőket jelenti:
Verziótartomány | Elérhető verziók | Kijelölt verzió |
---|---|---|
[1.0.0, 2.0.0) | 1.2.0-béta.1, 1.2.0, | 1.2.0 |
[1.0.0, 2.0.0-0) | 1.2.0-béta.1, 1.2.0, | 1.2.0-béta.1 |
[1.0.0, 2.0.0) | 1.2.0-béta.1, 2.0.0-béta.3 | Nincs, NU1103 van emelve. |
[1.0.0, 2.0.0-rc) | 1.2.0-béta.1, 2.0.0-béta.3 | 1.2.0-béta.1 |
A függőségek feloldása a packages.config-val
A packages.config
projekt függőségeit a packages.config
lapos listaként írja. A csomagok függőségei is ugyanabban a listában vannak megírva. A csomagok telepítésekor a NuGet módosíthatja a .csproj
fájlt, app.config
, web.config
és más egyéni fájlokat is.
A packages.config
-val a NuGet megpróbálja az egyes csomagok telepítése során feloldani a függőségi ütközéseket. Ez azt jelzi, hogy ha az A csomag telepítve van, és a B csomagtól függ, és a B csomag már szerepel a packages.config
valami más függőségeként, a NuGet összehasonlítja a kért B csomag verzióit, és megpróbálja megtalálni az összes verziókorlátozásnak megfelelő verziót. A NuGet a függőségeket kielégítő alsó major.minor verziót választja ki.
Alapértelmezés szerint a NuGet 2.8 a legalacsonyabb javításverziót keresi (lásd NuGet 2.8 kibocsátási megjegyzéseit). Ezt a beállítást a NuGet.Config
DependencyVersion
attribútumával és a parancssori -DependencyVersion
kapcsolóval szabályozhatja.
A függőségek feloldásának packages.config
folyamata bonyolultabb lesz a nagyobb függőségi grafikonok esetében. Minden új csomagtelepítéshez a teljes gráf bejárása szükséges, és növeli a verzióütközések esélyét. Ütközés esetén a telepítés leáll, így a projekt határozatlan állapotban marad, különösen a projektfájl esetleges módosításaival. Ez nem jelent problémát más csomagkezelési formátumok használatakor.
Verziótartományok és előzetes verziók packages.config
packages.config felbontás nem teszi lehetővé a stabil és a kiadás előtti függőségek keveredését egy gráfban.
Ha egy függőség olyan tartománysal van kifejezve, mint a [1.0.0, 2.0.0)
, a gráf nem engedélyezi a kiadás előtti csomagokat.
Függőségi eszközök kezelése
A PackageReference formátum használatakor szabályozhatja, hogy a függőségek mely eszközei áramlanak a legfelső szintű projektbe. További információ: PackageReference.
Ha a legfelső szintű projekt maga egy csomag, akkor az .nuspec
fájlban felsorolt függőségeket tartalmazó include
és exclude
attribútumokkal is szabályozhatja ezt a folyamatot. Lásd: .nuspec Reference – Függőségek.
Hivatkozások kizárása
Vannak olyan forgatókönyvek, amelyekben az azonos nevű összeállításokra többször is hivatkozhatnak egy projektben, és tervezéskor és építéskor hibákat okozhatnak. Fontolja meg egy olyan projektet, amely tartalmazza a C.dll
egyéni verzióját, és hivatkozik a C csomagra, amely szintén tartalmazza a C.dll
-et. Ugyanakkor a projekt a B csomagtól is függ, amely a C csomagtól és a C.dll
is függ. Ennek eredményeképpen a NuGet nem tudja meghatározni, hogy melyik C.dll
kell használni, de nem távolíthatja el egyszerűen a projekt C csomagtól való függőségét, mert a B csomag is függ attól.
A probléma megoldásához közvetlenül hivatkoznia kell a kívánt C.dll
(vagy egy másik, a megfelelőre hivatkozó csomagot kell használnia), majd hozzá kell adnia egy függőséget a C csomaghoz, amely kizárja az összes eszközét. Ez a használatban lévő csomagkezelési formátumtól függően az alábbiak szerint történik:
PackageReference:
ExcludeAssets="All"
hozzáadása a függőséghez:<PackageReference Include="PackageC" Version="1.0.0" ExcludeAssets="All" />
packages.config
: Távolítsa el a PackageC-ra mutató hivatkozást a.csproj
fájlból, hogy csak a kívántC.dll
verziójára hivatkozzon.
Függőségi frissítések a csomag telepítése során
Ha egy függőségi verzió már teljesül, a függőség nem frissül a többi csomagtelepítés során. Vegyük például az A csomagot, amely a B csomagtól függ, és 1.0-t ad meg a verziószámhoz. A forrásadattár a B csomag 1.0-s, 1.1-s és 1.2-s verzióját tartalmazza. Ha az A olyan projektben van telepítve, amely már tartalmazza a B 1.0-s verzióját, akkor a B 1.0 továbbra is használatban marad, mert megfelel a verziókorlátozásnak. Ha azonban az A csomag a B 1.1-es vagy újabb verzióját kéri, akkor a B 1.2 lesz telepítve.
Nem kompatibilis csomaghibák elhárítása
A csomag-visszaállítási művelet során a következő hibaüzenet jelenhet meg: "Egy vagy több csomag nem kompatibilis..." vagy hogy egy csomag "nem kompatibilis" a projekt cél-keretrendszerével.
Ez a hiba akkor fordul elő, ha a projektben hivatkozott egy vagy több csomag nem jelzi, hogy támogatják a projekt célkeretét; vagyis a csomag nem tartalmaz megfelelő DLL-t a lib
mappájában a projekttel kompatibilis cél-keretrendszerhez. (Lásd a(z) Célkeretrendszerek listáját.)
Ha például egy projekt netstandard1.6
céloz meg, és olyan csomagot próbál telepíteni, amely csak a lib\net20
és \lib\net45
mappákban tartalmaz DLL-eket, akkor az alábbihoz hasonló üzeneteket fog látni a csomaghoz és esetleg a függőségeihez:
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'.
Az inkompatibilitások feloldásához tegye az alábbiak egyikét:
- A projekt újraépítése olyan keretrendszerbe, amelyet a használni kívánt csomagok támogatnak.
- Lépjen kapcsolatba a csomagok szerzőjével, és működjön együtt velük, hogy támogatást adjon a kiválasztott keretrendszerhez. A nuget.org minden egyes csomaglistázási oldalához tartozik egy Tulajdonosok kapcsolatfelvétele hivatkozás erre a célra.
Borravaló
Alternatív megoldás: A NuGetSolver a Microsoft DevLabs által kifejlesztett Visual Studio-bővítmény, amely segít a függőségi ütközések megoldásában. Automatizálja a problémák azonosításának és megoldásának folyamatát. További részletekért látogasson el a NuGetSolver oldalára a Visual Studio Marketplace-en, és örömmel halljuk visszajelzését a felhasználói élményéről.