共用方式為


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 版:

選擇最低適用的版本

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

選擇訂閱源中可用的下一個最低版本

當應用程式指定一個無法在軟體源中找到的確切版本號碼,例如 1.2 時,NuGet 會在嘗試安裝或還原套件時報錯並失敗。

NuGet 在未提供確切套件版本時產生錯誤

浮動版本

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

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

要求浮動版本 6.0.* 時選擇 6.0.1 版

版本 伺服器上存在的版本 解析度 原因 筆記
* 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 版中使用
1.2.0-rc.* 1.1.0
1.2.0-rc.1
1.2.0-rc.2
1.2.0
1.2.0 儘管這是一個有預發行部分的版本範圍,但如果穩定版本符合穩定部分,則允許使用。 假設 1.2.0 > 1.2.0-rc.2,則會選擇它。

注意事項

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

直接相依性獲勝

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

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

使用直接相依性取勝規則的應用程式

警告

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

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

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

當 NuGet 忽略圖形中的某個套件時,它會忽略該整個分支

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

當套件作者明確降級時,NuGet 會遵循這一點。

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

當應用程式尊重新增降級套件的直接相依性時,NuGet 會承認此相依性。

表兄弟關係相依性

當應用程式的圖形中,不同子圖參考到不同的套件版本時,NuGet 會使用符合所有版本需求的最低版本(如同 最低適用版本浮動版本 規則)。 例如,在下圖中,套件 B 2.0.0 版符合另一个 >=1.0.0 的限制條件,因此會使用:

使用符合所有條件約束的較低版本來解決同系依賴

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

使用較低版本來解決親屬相依性,以滿足不同距離的所有限制條件

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

無法解決的相依性,由於確切的版本需求

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

PackageReference 的版本範圍和發行前版本

套件提供穩定和發行前版本並不罕見。 解析相依性圖形時,NuGet 會決定是否要根據單一規則考慮套件的發行前版本: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.

實際上,在最低適用的規則下,這表示:

版本範圍 可用的版本 選取的版本
[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 無,NU1103 已被引發。
[1.0.0,2.0.0-rc) 1.2.0-beta.1、2.0.0-beta.3 1.2.0-beta.1

使用 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 程序對於較大的相依性圖形而言會變得複雜。 每個新的套件安裝都需要遍歷整個圖表,並增加版本衝突的可能性。 發生衝突時,會停止安裝,使專案處於不確定狀態,特別是項目檔本身的潛在修改。 使用其他套件管理格式時,這不是問題。

版本範圍和發行前版本搭配 packages.config

packages.config 解析不允許在圖表中混合穩定和發行前版本相依性。 如果相依性是以類似 [1.0.0, 2.0.0)的範圍來表示,圖形中不允許發行前版本套件。

管理相依性資產

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

當最上層專案本身是一個套件時,您可以透過使用 includeexclude 屬性來控制此流程,這些屬性與 .nuspec 檔案中列出的相依性一起使用。 請參閱 .nuspec 參考 - 相依性

排除參考

在某些情況下,專案中可能會多次參考具有相同名稱的元件,產生設計時間和建置時間錯誤。 請考慮包含自定義版本的 C.dll專案,並參考也包含 C.dll的套件 C。 同時,專案也相依於套件 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 檔案中移除 PackageC 的參考,使其只參考您想要的 C.dll 版本。

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

如果相依性版本已經滿足,則相依性不會在其他套件安裝期間更新。 例如,請考慮相依於套件 B 的套件 A,並針對版本號碼指定 1.0。 來源存放庫包含 1.0、1.1 和 1.2 版的套件 B。如果 A 已安裝在已經包含 B 1.0 版的專案中,B 1.0 會繼續使用,因為它符合版本條件約束。 不過,如果套件 A 需要 B 的 1.1 版或更高版本,則會安裝 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 頁面,我們很樂意聽到您對體驗的意見反應。