NuGet がパッケージの依存関係を解決する方法
パッケージがインストールまたは再インストールされるたびに (復元 プロセスの一部としてインストールされる場合を含む)、NuGet はその最初のパッケージが依存する追加パッケージもインストールします。
これらの即時の依存関係には、独自の依存関係があり、任意の深さに続く可能性があります。 これにより、すべてのレベルのパッケージ間のリレーションシップを記述する 依存関係グラフ と呼ばれるものが生成されます。
複数のパッケージが同じ依存関係を持つ場合、同じパッケージ ID がグラフに複数回表示される可能性があり、バージョンの制約が異なる可能性があります。 ただし、プロジェクトで使用できるパッケージのバージョンは 1 つだけであるため、NuGet では使用するバージョンを選択する必要があります。 正確なプロセスは、使用されているパッケージ管理形式によって異なります。
PackageReference を使用した依存関係の解決
PackageReference 形式を使用してパッケージをプロジェクトにインストールする場合、NuGet は適切なファイル内のフラット パッケージ グラフへの参照を追加し、競合を事前に解決します。 このプロセスは、推移的な復元と呼ばれます。 パッケージの再インストールまたは復元は、グラフに一覧表示されているパッケージをダウンロードするプロセスであり、その結果、より高速で予測可能なビルドになります。
また、2.8.* などの浮動バージョンを利用して、パッケージの最新バージョンを使用するようにプロジェクトを変更しないようにすることもできます。 フローティング バージョンを使用する場合は、繰り返し性を確保するために、ロック ファイル機能 を有効にすることをお勧めします。
ビルドの前に NuGet 復元プロセスが実行されると、まずメモリ内の依存関係が解決され、結果のグラフが project.assets.json
というファイルに書き込まれます。
アセット ファイルは MSBuildProjectExtensionsPath
にあり、既定ではプロジェクトの 'obj' フォルダーになります。
MSBuild は、このファイルを読み取り、潜在的な参照が見つかるフォルダーのセットに変換し、メモリ内のプロジェクト ツリーに追加します。
project.assets.json
ファイルは一時的なものであり、ソース管理に追加しないでください。
.gitignore
と .tfignore
の両方に既定で表示されます。 「パッケージとソース管理の」を参照してください。
依存関係解決規則
推移的な復元では、依存関係を解決するための 4 つの主要なルールが適用されます。適用可能な最小バージョンの、浮動バージョン、直接依存関係優先、および いとこ依存関係。
適用可能な最小バージョン
適用可能なバージョンの最小規則では、依存関係によって定義されているパッケージの可能な限り低いバージョンが復元されます。 宣言時に 浮動として記されていない限り、アプリケーションやクラスライブラリの依存関係にも適用されます。
次の図では、たとえば、1.0 ベータは 1.0 より低いと見なされるため、NuGet は 1.0 バージョンを選択します。
次の図では、バージョン 2.1 はフィードでは使用できませんが、バージョン制約が >= 2.1 であるため、NuGet は次に見つかる最も低いバージョン (この場合は 2.2) を選択します。
で利用可能な次の最小バージョンの選択
フィードで使用できない正確なバージョン番号 (1.2 など) がアプリケーションで指定されている場合、NuGet はパッケージをインストールまたは復元しようとしたときにエラーで失敗します。
フローティング・バージョン
浮動依存関係バージョンは* 文字で指定されます。 たとえば、6.0.*
します。 このバージョンの仕様では、"最新の 6.0.x バージョンを使用する" と表示されます。4.*
は、"最新の 4.x バージョンを使用する" を意味します。フローティング バージョンを使用すると、依存関係の最新バージョンを最新の状態に保ちながら、プロジェクト ファイルの変更を減らすことができます。
浮動バージョンは、プロジェクト レベルでのみ指定できます。
浮動バージョンを使用する場合、NuGet はバージョン パターンに一致するパッケージの最高バージョンを解決します。たとえば、6.0.*
は 6.0 で始まるパッケージの最高バージョンを取得します。
バージョン | サーバーに存在するバージョン | 解決 | 理由 | ノート |
---|---|---|---|---|
* | 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-アルファ版 |
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 があることを考慮して、それが選択されます。 |
手記
フローティング バージョン解決では、パッケージが一覧表示されているかどうかは考慮されません。 グローバル パッケージ フォルダー内のパッケージで条件を満たすことができる場合、フローティング バージョン解決はローカルで解決されます。
直接依存関係の優先
アプリケーションのパッケージ グラフに同じサブグラフ内に異なるバージョンのパッケージが含まれており、それらのバージョンの 1 つがサブグラフ内の直接の依存関係である場合、そのサブグラフに対してそのバージョンが選択され、残りは無視されます。 この動作により、アプリケーションは依存関係グラフ内の特定のパッケージ バージョンをオーバーライドできます。
次の例では、アプリケーションはパッケージ B に直接依存し、バージョン制約は >=2.0.0 です。 アプリケーションもパッケージ A に依存し、パッケージ B にも依存しますが、>=1.0.0 制約が適用されます。 パッケージ B 2.0.0 への依存関係はグラフ内のアプリケーションに直接依存するため、そのバージョンが使用されます。
「直接依存関係が優先されるルールを使用したアプリケーションの 」
警告
直接依存関係優先ルールによりパッケージ バージョンがダウングレードされ、グラフ内の他の依存関係が破損する可能性があります。 パッケージがダウングレードされると、NuGet によって 警告が追加され、ユーザーに警告が表示されます。
このルールにより、大きな依存関係グラフの効率も向上します。 同じサブグラフのより近い依存関係のバージョンがそれ以上のバージョンである場合、NuGet はその依存関係を無視し、NuGet はグラフのその分岐に対する残りの依存関係もすべて無視します。
次の図では、たとえば、パッケージ C 2.0.0 が使用されているため、NuGet は、以前のバージョンのパッケージ C を参照するサブグラフ内のすべての分岐を無視します。
全体が無視されます
この規則を通じて、NuGet はパッケージ作成者の意図を尊重しようとします。 次の図では、パッケージ A の作成者がパッケージ C 2.0.0 からパッケージ C 1.0.0 に明示的にダウングレードされています。
アプリケーション所有者は、パッケージ C を 2.0.0 より高いバージョンにアップグレードすることを選択できるため、パッケージ C のバージョンをそれ以上ダウングレードすることはできません。この場合、警告は発生しません。
いとこの依存関係
アプリケーションからグラフ内の異なるサブグラフで異なるパッケージ バージョンが参照されている場合、NuGet では、すべてのバージョン要件を満たす最小バージョンが使用されます (適用可能なバージョン が最も低い と、浮動バージョン 規則)。 次の図では、たとえば、パッケージ B のバージョン 2.0.0 が他の >=1.0.0 制約を満たしているため、使用されています。
いとこの依存関係ルールを適用するために、パッケージが同じ距離にある必要はありません。 次の図では、パッケージ D 2.0.0 が Package C サブグラフで選択され、パッケージ 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.
実際には、適用される最も低い規則では、次のことを意味します。
packages.config を使用した依存関係の解決
packages.config
では、プロジェクトの依存関係がフラット リストとして packages.config
に書き込まれます。 これらのパッケージの依存関係も同じリストに書き込まれます。 パッケージがインストールされると、NuGet によって、.csproj
ファイル、app.config
、web.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 を参照してください。
最上位のプロジェクト自体がパッケージである場合は、.nuspec
ファイルに一覧表示されている依存関係を持つ include
属性と exclude
属性を使用して、このフローを制御することもできます。 「.nuspec リファレンス - 依存関係の」を参照してください。
参照を除外する
プロジェクトで同じ名前のアセンブリが複数回参照され、デザイン時エラーとビルド時エラーが発生するシナリオがあります。
C.dll
のカスタム バージョンを含み、C.dll
も含むパッケージ C を参照するプロジェクトを考えてみましょう。 同時に、プロジェクトはパッケージBにも依存し、パッケージCと C.dll
にも依存します。 その結果、NuGet はどの C.dll
を使用するかを判断できませんが、パッケージ B もそれに依存しているため、パッケージ C に対するプロジェクトの依存関係を削除することはできません。
これを解決するには、必要な C.dll
を直接参照し (または適切なものを参照する別のパッケージを使用して)、そのすべての資産を除外するパッケージ C への依存関係を追加する必要があります。 これは、使用されているパッケージ管理の形式に応じて、次のように行われます。
PackageReference: 依存関係に
ExcludeAssets="All"
を追加します。<PackageReference Include="PackageC" Version="1.0.0" ExcludeAssets="All" />
packages.config
:.csproj
ファイルから PackageC への参照を削除し、必要なバージョンのC.dll
のみを参照するようにします。
パッケージのインストール中の依存関係の更新
依存関係のバージョンが既に満たされている場合、依存関係は他のパッケージのインストール中に更新されません。 たとえば、パッケージ B に依存し、バージョン番号に 1.0 を指定するパッケージ A があるとします。 ソース リポジトリには、パッケージ B のバージョン 1.0、1.1、および 1.2 が含まれています。既に B バージョン 1.0 を含むプロジェクトに A がインストールされている場合、B 1.0 はバージョン制約を満たしているため、引き続き使用されます。 ただし、パッケージ A に要求バージョン 1.1 以上の B がある場合は、B 1.2 がインストールされます。
互換性のないパッケージ エラーの解決
パッケージの復元操作中に、「1 つ以上のパッケージに互換性がありません...」というエラーが表示されることがあります。または、パッケージがプロジェクトのターゲット フレームワークと "互換性がありません" ことを示します。
このエラーは、プロジェクトで参照されている 1 つ以上のパッケージがプロジェクトのターゲット フレームワークをサポートしていることを示していない場合に発生します。つまり、パッケージには、プロジェクトと互換性のあるターゲット フレームワークの 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 ページを参照してください。お客様のエクスペリエンスに関するフィードバックをお寄せください。