NuGet 如何解析套件相依性

只要安裝或重新安裝套件 (包含安裝為還原程序一部分的套件),NuGet 也會安裝與這個第一個套件相依的任何其他套件。

這些立即相依性接著會有其自己的相依性,而這會繼續到任意深度。 這會產生所謂的「相依性圖形」,以描述所有層級上套件之間的關聯性。

多個套件具有相同的相依性時,同一個套件識別碼可能會多次出現在圖形中,但可能具有不同版本的條件約束。 不過,專案中只能使用一個指定套件的版本,因此 NuGet 必須選擇要使用的版本。 確切的處理序取決於所使用的套件管理格式。

使用 PackageReference 的相依性解析

使用 PackageReference 格式來將套件安裝至專案時,NuGet 會新增適當檔案中一般套件圖形的參考,並事先解決衝突。 此程序稱為「可轉移還原」。 重新安裝或還原套件則是下載圖形中所列套件的程序,導致更快速且更容易預測的組建。

您也可以利用浮動版本,例如 2.8.*,以避免修改專案以使用最新版本的套件。 使用浮動版本時,建議您啟用 鎖定檔案功能 ,以確保可重複性。

若 NuGet 還原程序在建置之前執行,就會先解析記憶體中的相依性,然後將產生的圖形寫入稱為 project.assets.json 的檔案。

資產檔案位於 MSBuildProjectExtensionsPath,其預設為專案的 'obj' 資料夾。 MSBuild 接著會讀取這個檔案,並將它轉譯成一組可找到可能參考的資料夾,然後將它們新增至記憶體中的專案樹狀結構。

project.assets.json 檔案是暫時的,不應該新增至原始程式碼控制。 它預設會列在 .gitignore.tfignore 中。 請參閱套件和原始檔控制

相依性解析規則

可轉移還原會套用四個主要規則來解決相依性:最低適用的版本、浮動版本直接相依性與表親相依性

最低適用版本

最低適用版本規則可還原依其相依性所定義之最低可能版本的套件。 除非宣告為浮動,否則它也適用於與應用程式或類別庫的相依性。

例如,在下圖中,將 1.0-beta 視為低於 1.0,因此 NuGet 會選擇 1.0 版:

Choosing the lowest applicable version

在下一個圖中,摘要上無法使用 2.1 版,但因為版本條件約束是 >= 2.1 NuGet 會挑選下一個可以找到的最低版本,在此案例中為 2.2:

Choosing the next lowest version available on the feed

如果應用程式指定不適用於摘要的確切版本號碼 (例如 1.2),則嘗試安裝或還原套件時,NuGet 會失敗並發生錯誤:

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

浮動版本

使用 * 字元指定浮動相依性版本。 例如: 6.0.* 。 此版本規格指出「使用最新的 6.0.x 版」; 4.* 表示「使用最新的 4.x 版本」。使用浮動版本可減少專案檔的變更,同時保持最新版的相依性。 浮動版本只能在專案層級指定。

使用浮動版本時,NuGet 會解析符合版本模式的最高套件版本,例如 6.0.* 取得以 6.0 開頭的最高套件版本:

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

版本 伺服器上存在的版本 解決方法 原因 備註
* 1.1.0
1.1.1
1.2.0
1.3.0-alpha
1.2.0 最高的穩定版本。
1.1.* 1.1.0
1.1.1
1.1.2-alpha
1.2.0-alpha
1.1.1 符合指定模式的最高穩定版本。
*-* 1.1.0
1.1.1
1.1.2-alpha
1.3.0-beta
1.3.0-beta 最高版本,包括不穩定的版本。 可在 Visual Studio 16.6 版、NuGet 5.6 版、.NET Core SDK 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 與模式相關的最高版本,包括不穩定的版本。 可在 Visual Studio 16.6 版、NuGet 5.6 版、.NET Core SDK 3.1.300 版中使用

注意

浮動版本解析不會考慮是否列出套件。 如果條件可以符合全域封裝資料夾中的套件,則會在本機解析浮動版本解析。

直接相依性獲勝

當應用程式的套件圖形包含相同子檔中不同版本的套件時,而其中一個版本是該子檔中的直接相依性,則會針對該子圖形選擇該版本,而其餘版本則會忽略。 此行為允許應用程式覆寫相依性圖形中的任何特定套件版本。

在下列範例中,應用程式直接相依於套件 B,版本條件約束為 >=2.0.0。 應用程式也相依於套件 A,而封裝 A 則依存於套件 B,但具有 >=1.0.0 條件約束。 因為套件 B 2.0.0 上的相依性是圖形中應用程式的直接相依性,因此會使用該版本:

Application using the Direct dependency wins rule

警告

直接相依性獲勝規則可能會導致套件版本的降級,因此可能會中斷圖形中的其他相依性。 降級套件時,NuGet 會新增 警告來警示使用者

此規則也會導致大型相依性圖表的效率更高。 當相同子檔中的相依性比進一步的相依性更高時,NuGet 會忽略該相依性,而 NuGet 也會忽略圖形該分支上所有剩餘的相依性。

例如,在下圖中,因為使用 Package C 2.0.0,NuGet 會忽略該子文件中參考舊版 Package C 的任何分支:

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

透過此規則,NuGet 會嘗試接受套件作者的意圖。 在下圖中,套件 A 的作者已從 Package C 2.0.0 明確降級為 Package C 1.0.0。

When a package author explicitly downgrades, NuGet honors that.

應用程式擁有者可以選擇將套件 C 升級至高於 2.0.0 的版本,因此不會進一步降級套件 C 的版本。在此情況下,不會引發任何警告。

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

鄰近相依性

當圖形中的不同子文件中參考不同的套件版本時,NuGet 會使用符合所有版本需求的最低版本(如同 最低適用的版本浮動版本 規則)。 例如,在下圖中,套件 B 2.0.0 版滿足另一個 >=1.0.0 條件約束,因此會使用:

Resolving cousin dependencies using the lower version that satisfies all constraints

請注意,套件不需要位於要套用之表親相依性規則的相同距離。 在下圖中,Package D 2.0.0 是在 Package C 子文件中選擇,而 Package D D 3.0.0 則是在套件 A 的子文件中選擇。在 [應用程式] 子檔中,沒有套件 D 的直接相依性,因此 會套用最低適用的版本 規則,並選擇 3.0.0 版。

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

在某些情況下,無法符合所有版本需求。 如下所示,如果套件 A 需要套件 B 1.0.0,而套件 C 需要套件 B >=2.0.0,則 NuGet 無法解析相依性併產生錯誤。

Unresolvable dependencies due to an exact version requirement

在這些情況下,最上層取用者(應用程式或套件)應該在套件 B 上新增自己的直接相依性, 以便套用直接相依性取用 規則。

使用 packages.config 的相依性解析

使用 packages.config,專案的相依性會寫入至 packages.config 作為一般清單。 這些套件的任何相依性也會寫入相同的清單中。 安裝套件之後,NuGet 也可能會修改 .csproj 檔案、app.configweb.config 和其他個別檔案。

使用 packages.config,NuGet 會嘗試在每個個別套件安裝期間解決相依性衝突。 也就是說,如果套件 A 已安裝並與套件 B 相依,而且套件 B 已列在 packages.config 中作為其他項目的相依性,則 NuGet 會比較所要求的套件 B 版本,並嘗試找到符合所有版本條件約束的版本。 具體來說,NuGet 會選取符合相依性的較低 major.minor 版本。

根據預設,NuGet 2.8 會尋找最低的修補程式版本 (請參閱 NuGet 2.8 版本資訊)。 您可以透過 NuGet.Config 中的 DependencyVersion 屬性和命令列上的 -DependencyVersion 參數,來控制此設定。

針對較大的相依性圖形,解析相依性的 packages.config 程序會更為複雜。 每個新套件安裝都需要周遊整個圖形,而且會引發版本衝突機會。 發生衝突時,會停止安裝,並讓專案處於不定狀態,特別是對專案檔本身進行可能的修改。 使用其他套件管理格式時,這不是問題。

管理相依性資產

使用 PackageReference 格式時,您可以控制從相依性流入最上層專案的資產。 如需詳細資訊,請參閱 PackageReference

最上層專案本身是套件時,也可以搭配使用 includeexclude 屬性與 .nuspec 檔案中所列相依性來控制此流量。 請參閱 .nuspec 參考 - 相依性

排除參考

在某些情況下,可能會在專案中多次參考同名的組件,並產生設計階段和建置時間錯誤。 請考慮包含 C.dll 之自訂版本的專案,並參考也包含 C.dll 的套件 C。 同時,專案也與套件 B 相依,而套件 B 也與套件 C 和 C.dll 相依。 因此,NuGet 無法決定要使用的 C.dll,但您不能只移除專案與套件 C 的相依性,因為套件 B 也與其相依。

若要解決此問題,您必須直接參考想要的 C.dll (或使用另一個參考正確項目的套件),然後新增與排除所有資產之套件 C 的相依性。 這是根據使用中的套件管理格式所進行,如下所示:

  • PackageReference:在相依性中新增 ExcludeAssets="All"

    <PackageReference Include="PackageC" Version="1.0.0" ExcludeAssets="All" />
    
  • packages.config:從 .csproj 檔案中移除套件 C 的參考,讓它只參考您想要的 C.dll 版本。

套件安裝期間的相依性更新

如果已符合相依性版本,則不會在其他套件安裝期間更新相依性。 例如,請考慮使用與套件 B 相依並指定 1.0 作為版本號碼的套件 A。 來源存放庫包含 1.0、1.1 和 1.2 版的套件 B。如果在已包含 B 1.0 版的專案中安裝 A,則 B 1.0 仍會維持使用中狀態,因為它符合版本限制。 不過,如果套件 A 要求 1.1 版或更高版本的 B,則會安裝 B 1.2。

解決不相容的套件錯誤

在套件還原作業期間,您可能會看到「一或多個套件不相容...」錯誤,或套件與專案目標架構「不相容」。

專案中參考的一或多個套件未指出它們支援專案的目標架構時,會發生此錯誤;也就是說,套件在其 lib 資料夾中未包含與專案相容之目標架構的適合 DLL (如需清單,請參閱目標架構)。

例如,如果專案的目標設為 netstandard1.6,而且您嘗試安裝只包含 lib\net20\lib\net45 資料夾中 DLL 的套件,則會看到套件和其相依項的下列這類訊息:

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

若要解決不相容,請執行下列其中一項:

  • 將專案的目標重新設為您想要使用的套件所支援的架構。
  • 請連絡套件作者,並與他們合作以新增所選擇架構的支援。 基於此用途,nuget.org 上的每個套件列出頁面都具有連絡人負責人連結。

提示

替代解決方案:NuGetSolver 是由 Microsoft DevLabs 開發的 Visual Studio 延伸模組,其設計目的是協助解決相依性衝突。 它會自動化識別和解決這些問題的程式。 如需進一步的詳細數據,請流覽 Visual Studio Marketplace上的 NuGetSolver 頁面,我們很樂意聽到您對體驗的意見反應。