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:

Choosing the lowest applicable version

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:

Choosing the next lowest version available on the feed

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:

NuGet generates an error when an exact package version is not available

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:

Choosing version 6.0.1 when a floating version 6.0.* is requested

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:

Application using the Direct dependency wins rule

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:

When NuGet ignores a package in the graph, it ignores that entire branch

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.

When a package author explicitly downgrades, NuGet honors that.

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.

When an application honor adds a direct dependency for a downgraded package, NuGet honors that.

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:

Resolving cousin dependencies using the lower version that satisfies all constraints

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.

Resolving cousin dependencies using the lower version that satisfies all constraints at different distances

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.

Unresolvable dependencies due to an exact version requirement

Dalam situasi ini, konsumen tingkat atas (aplikasi atau paket) harus menambahkan dependensi langsungnya sendiri pada Paket B sehingga aturan Kemenangan dependensi langsung berlaku.

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.configweb.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.

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.dllkustom , 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 versi C.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.