Cara NuGet mengatasi dependensi paket
Setiap kali paket diinstal atau diinstal ulang, yang mencakup diinstal sebagai bagian dari proses pemulihan , NuGet juga menginstal paket tambahan yang bergantung pada paket pertama tersebut.
Dependensi langsung tersebut kemudian mungkin juga memiliki dependensi sendiri, yang dapat berlanjut ke kedalaman semena-mena. Ini menghasilkan apa yang disebut grafik dependensi yang menjelaskan hubungan antara paket di semua tingkatan.
Ketika beberapa paket memiliki dependensi yang sama, MAKA ID paket yang sama dapat muncul dalam grafik beberapa kali, berpotensi dengan batasan versi yang berbeda. Namun, hanya satu versi paket tertentu yang dapat digunakan dalam proyek, jadi NuGet harus memilih versi mana yang digunakan. Proses yang tepat tergantung pada format manajemen paket yang digunakan.
Resolusi dependensi dengan PackageReference
Saat menginstal paket ke dalam proyek menggunakan format PackageReference, NuGet menambahkan referensi ke grafik paket datar dalam file yang sesuai dan menyelesaikan konflik sebelumnya. Proses ini disebut sebagai pemulihan transitif. Menginstal ulang atau memulihkan paket kemudian adalah proses mengunduh paket yang tercantum dalam grafik, menghasilkan build yang lebih cepat dan lebih dapat diprediksi.
Anda juga dapat memanfaatkan versi mengambang, seperti 2.8.*, untuk menghindari memodifikasi proyek untuk menggunakan versi terbaru paket. Saat menggunakan versi mengambang, sebaiknya aktifkan fungsionalitas file kunci untuk memastikan pengulangan.
Ketika proses pemulihan NuGet berjalan sebelum build, proses tersebut menyelesaikan dependensi terlebih dahulu dalam memori, lalu menulis grafik yang dihasilkan ke file yang disebut project.assets.json
.
File aset terletak di MSBuildProjectExtensionsPath
, yang default ke folder 'obj' proyek.
MSBuild kemudian membaca file ini dan menerjemahkannya ke dalam sekumpulan folder tempat referensi potensial dapat ditemukan, lalu menambahkannya ke pohon proyek dalam memori.
File project.assets.json
bersifat sementara dan tidak boleh ditambahkan ke kontrol sumber. Ini tercantum secara default di dan .gitignore
.tfignore
. Lihat Paket dan kontrol sumber.
Aturan resolusi dependensi
Pemulihan transitif menerapkan empat aturan utama untuk mengatasi dependensi: versi terendah yang berlaku, versi mengambang, direct-dependency-wins, dan dependensi sepupu.
Versi terendah yang berlaku
Aturan versi serendah yang berlaku memulihkan versi paket serendah mungkin seperti yang ditentukan oleh dependensinya. Ini juga berlaku untuk dependensi pada aplikasi atau pustaka kelas kecuali dinyatakan sebagai mengambang.
Dalam gambar berikut, misalnya, 1.0-beta dianggap lebih rendah dari 1,0 sehingga NuGet memilih versi 1.0:
Pada gambar berikutnya, versi 2.1 tidak tersedia di umpan tetapi karena batasan versi adalah >= 2.1 NuGet memilih versi terendah berikutnya yang dapat ditemukannya, dalam hal ini 2.2:
Ketika aplikasi menentukan nomor versi yang tepat, seperti 1.2, yang tidak tersedia pada umpan, NuGet gagal dengan kesalahan saat mencoba menginstal atau memulihkan paket:
Versi mengambang
Versi dependensi mengambang ditentukan dengan karakter * . Contohnya,6.0.*
. Spesifikasi versi ini mengatakan "gunakan versi 6.0.x terbaru"; 4.*
berarti "gunakan versi 4.x terbaru." Menggunakan versi mengambang mengurangi perubahan pada file proyek, sambil tetap mendapatkan informasi terbaru tentang versi dependensi terbaru.
Versi mengambang hanya dapat ditentukan pada tingkat proyek.
Saat menggunakan versi mengambang, NuGet menyelesaikan versi tertinggi paket yang cocok dengan pola versi, misalnya 6.0.*
mendapatkan versi tertinggi dari paket yang dimulai dengan 6.0:
Versi | Versi yang ada di server | Resolusi | Alasan | Catatan |
---|---|---|---|---|
* | 1.1.0 1.1.1 1.2.0 1.3.0-alpha |
1.2.0 | Versi stabil tertinggi. | |
1.1.* | 1.1.0 1.1.1 1.1.2-alpha 1.2.0-alpha |
1.1.1 | Versi stabil tertinggi yang menghormati pola yang ditentukan. | |
*-* | 1.1.0 1.1.1 1.1.2-alpha 1.3.0-beta |
1.3.0-beta | Versi tertinggi termasuk versi yang tidak stabil. | Tersedia di Visual Studio versi 16.6, NuGet versi 5.6, .NET Core SDK versi 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 | Versi tertinggi yang menghormati pola dan menyertakan versi yang tidak stabil. | Tersedia di Visual Studio versi 16.6, NuGet versi 5.6, .NET Core SDK versi 3.1.300 |
Catatan
Resolusi versi mengambang tidak memperhitungkan apakah paket terdaftar atau tidak. Resolusi versi mengambang akan diselesaikan secara lokal jika kondisi dapat dipenuhi dengan paket di Folder Paket Global.
Dependensi langsung menang
Ketika grafik paket untuk aplikasi berisi versi paket yang berbeda dalam subgraf yang sama, dan salah satu versi tersebut adalah dependensi langsung dalam subgraf tersebut, versi tersebut akan dipilih untuk subgraf tersebut dan sisanya akan diabaikan. Perilaku ini memungkinkan aplikasi untuk mengambil alih versi paket tertentu dalam grafik dependensi.
Dalam contoh di bawah ini, aplikasi bergantung langsung pada Paket B dengan batasan >versi =2.0.0. Aplikasi juga bergantung pada Paket A yang pada gilirannya juga bergantung pada Paket B, tetapi dengan >batasan =1.0.0. Karena dependensi pada Paket B 2.0.0 adalah dependensi langsung ke aplikasi dalam grafik, versi tersebut digunakan:
Peringatan
Aturan Kemenangan dependensi langsung dapat mengakibatkan penurunan versi paket, sehingga berpotensi merusak dependensi lain dalam grafik. Saat paket diturunkan, NuGet menambahkan peringatan untuk memperingatkan pengguna.
Aturan ini juga menghasilkan efisiensi yang lebih besar dengan grafik dependensi besar. Ketika dependensi yang lebih dekat dalam subgraf yang sama memiliki versi yang lebih tinggi daripada yang lebih lanjut, maka NuGet mengabaikan dependensi tersebut, dan NuGet juga mengabaikan semua dependensi yang tersisa pada cabang grafik tersebut.
Dalam diagram di bawah ini, misalnya, karena Paket C 2.0.0 digunakan, NuGet mengabaikan cabang apa pun dalam subgraf yang merujuk ke versi Paket C yang lebih lama:
Melalui aturan ini, NuGet mencoba menghormati niat penulis paket. Dalam diagram di bawah ini, penulis Paket A secara eksplisit menurunkan ke Paket C 1.0.0 dari Paket C 2.0.0.
Pemilik aplikasi dapat memilih untuk meningkatkan Paket C ke versi yang lebih tinggi dari 2.0.0, sehingga tidak ada penurunan versi lebih lanjut untuk Paket C. Dalam hal ini, tidak ada peringatan yang dimunculkan.
Dependensi sepupu
Ketika versi paket yang berbeda dirujuk dalam subgraf yang berbeda dalam grafik dari aplikasi, NuGet menggunakan versi terendah yang memenuhi semua persyaratan versi (seperti versi terendah yang berlaku dan aturan versi mengambang). Pada gambar di bawah ini, misalnya, Paket B versi 2.0.0 memenuhi batasan =1.0.0 lainnya >, dan dengan demikian digunakan:
Perhatikan bahwa paket tidak perlu berada pada jarak yang sama agar aturan dependensi sepupu diterapkan. Dalam diagram di bawah ini, Paket D 2.0.0 dipilih dalam subgraf Paket C dan Paket D 3.0.0 dipilih dalam subgraf Paket A. Dalam subgraf Aplikasi, tidak ada dependensi langsung ke Paket D, sehingga aturan versi terendah yang berlaku diterapkan dan versi 3.0.0 dipilih.
Dalam beberapa kasus, tidak dimungkinkan untuk memenuhi semua persyaratan versi. Seperti yang ditunjukkan di bawah ini, jika Paket A memerlukan Paket B 1.0.0 dan Paket C membutuhkan Paket B >=2.0.0, maka NuGet tidak dapat menyelesaikan dependensi dan memberikan kesalahan.
Dalam situasi ini, konsumen tingkat atas (aplikasi atau paket) harus menambahkan dependensi langsungnya sendiri pada Paket B sehingga aturan Kemenangan dependensi langsung berlaku.
Rentang versi dan versi prarilis dengan PackageReference
Tidak biasa bagi paket untuk memiliki versi stabil dan prarilis yang tersedia.
Saat menyelesaikan grafik dependensi, NuGet memutuskan apakah akan mempertimbangkan versi prarilis untuk paket berdasarkan satu aturan: 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.
Dalam praktiknya, di bawah aturan terendah yang berlaku, ini berarti:
Rentang Versi | Versi yang tersedia | Versi yang dipilih |
---|---|---|
[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 | Tidak ada, NU1103 dinaikkan. |
[1.0.0, 2.0.0-rc) | 1.2.0-beta.1, 2.0.0-beta.3 | 1.2.0-beta.1 |
Resolusi dependensi dengan packages.config
Dengan packages.config
, dependensi proyek ditulis sebagai packages.config
daftar datar. Dependensi apa pun dari paket tersebut juga ditulis dalam daftar yang sama. Ketika paket diinstal, NuGet mungkin juga memodifikasi .csproj
file, , app.config
web.config
, dan file individual lainnya.
Dengan packages.config
, NuGet mencoba mengatasi konflik dependensi selama penginstalan setiap paket individu. Artinya, jika Paket A sedang diinstal dan tergantung pada Paket B, dan Paket B sudah terdaftar packages.config
sebagai dependensi dari sesuatu yang lain, NuGet membandingkan versi Paket B yang diminta dan mencoba menemukan versi yang memenuhi semua batasan versi. Secara khusus, NuGet memilih versi major.minor yang lebih rendah yang memenuhi dependensi.
Secara default, NuGet 2.8 mencari versi patch terendah (lihat catatan rilis NuGet 2.8). Anda dapat mengontrol pengaturan ini melalui DependencyVersion
atribut di NuGet.Config
dan -DependencyVersion
sakelar pada baris perintah.
Proses packages.config
untuk menyelesaikan dependensi menjadi rumit untuk grafik dependensi yang lebih besar. Setiap penginstalan paket baru memerlukan traversal seluruh grafik dan meningkatkan kesempatan untuk konflik versi. Ketika konflik terjadi, penginstalan dihentikan, meninggalkan proyek dalam keadaan yang tidak ditentukan, terutama dengan potensi modifikasi pada file proyek itu sendiri. Ini bukan masalah saat menggunakan format manajemen paket lainnya.
Rentang versi dan versi prarilis dengan packages.config
resolusi packages.config tidak memungkinkan pencampuran dependensi stabil dan pra-rilis dalam grafik.
Jika dependensi dinyatakan dengan rentang seperti [1.0.0, 2.0.0)
, paket pra-rilis tidak diizinkan dalam grafik.
Mengelola aset dependensi
Saat menggunakan format PackageReference, Anda dapat mengontrol aset mana dari dependensi yang mengalir ke proyek tingkat atas. Untuk detailnya, lihat PackageReference.
Ketika proyek tingkat atas itu sendiri adalah paket, Anda juga memiliki kontrol atas alur ini dengan menggunakan include
atribut dan exclude
dengan dependensi yang tercantum dalam .nuspec
file. Lihat Referensi .nuspec - Dependensi.
Mengecualikan referensi
Ada skenario di mana rakitan dengan nama yang sama mungkin direferensikan lebih dari sekali dalam proyek, menghasilkan kesalahan waktu desain dan build-time. Pertimbangkan proyek yang berisi versi C.dll
kustom , dan referensi Paket C yang juga berisi C.dll
. Pada saat yang sama, proyek juga tergantung pada Paket B yang juga tergantung pada Paket C dan C.dll
. Akibatnya, NuGet tidak dapat menentukan mana yang C.dll
akan digunakan, tetapi Anda tidak dapat menghapus dependensi proyek pada Paket C karena Paket B juga bergantung padanya.
Untuk mengatasinya, Anda harus langsung mereferensikan C.dll
yang Anda inginkan (atau menggunakan paket lain yang mereferensikan paket yang tepat), lalu menambahkan dependensi pada Paket C yang mengecualikan semua asetnya. Ini dilakukan sebagai berikut tergantung pada format manajemen paket yang digunakan:
PackageReference: tambahkan
ExcludeAssets="All"
dalam dependensi:<PackageReference Include="PackageC" Version="1.0.0" ExcludeAssets="All" />
packages.config
: hapus referensi ke PackageC dari.csproj
file sehingga hanya mereferensikan versiC.dll
yang Anda inginkan.
Pembaruan dependensi selama penginstalan paket
Jika versi dependensi sudah terpenuhi, dependensi tidak diperbarui selama penginstalan paket lainnya. Misalnya, pertimbangkan paket A yang bergantung pada paket B dan menentukan 1.0 untuk nomor versi. Repositori sumber berisi versi 1.0, 1.1, dan 1.2 paket B. Jika A diinstal dalam proyek yang sudah berisi B versi 1.0, maka B 1.0 tetap digunakan karena memenuhi batasan versi. Namun, jika paket A memiliki permintaan versi 1.1 atau lebih tinggi dari B, maka B 1.2 akan diinstal.
Mengatasi kesalahan paket yang tidak kompatibel
Selama operasi pemulihan paket, Anda mungkin melihat kesalahan "Satu atau beberapa paket tidak kompatibel..." atau bahwa paket "tidak kompatibel" dengan kerangka kerja target proyek.
Kesalahan ini terjadi ketika satu atau beberapa paket yang dirujuk dalam proyek Anda tidak menunjukkan bahwa paket tersebut mendukung kerangka kerja target proyek; artinya, paket tidak berisi DLL yang sesuai di foldernya lib
untuk kerangka kerja target yang kompatibel dengan proyek. (Lihat Kerangka kerja target untuk daftar.)
Misalnya, jika proyek menargetkan netstandard1.6
dan Anda mencoba menginstal paket yang berisi DLL hanya lib\net20
di folder dan \lib\net45
, maka Anda melihat pesan seperti berikut untuk paket dan mungkin dependennya:
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'.
Untuk mengatasi ketidaksesuaian, lakukan salah satu hal berikut:
- Targetkan ulang proyek Anda ke kerangka kerja yang didukung oleh paket yang ingin Anda gunakan.
- Hubungi pembuat paket dan bekerja dengan mereka untuk menambahkan dukungan untuk kerangka kerja yang Anda pilih. Setiap halaman daftar paket di nuget.org memiliki tautan Pemilik Kontak untuk tujuan ini.
Tip
Solusi alternatif: NuGetSolver adalah Ekstensi Visual Studio yang dikembangkan oleh Microsoft DevLabs, yang dirancang untuk membantu menyelesaikan konflik dependensi. Ini mengotomatiskan proses mengidentifikasi dan mengatasi masalah ini. Untuk detail lebih lanjut, kunjungi halaman NuGetSolver di Visual Studio Marketplace dan kami ingin mendengar umpan balik Anda tentang pengalaman Anda.