アセンブリは、ビルド中に 2 つの異なる方法で使用されます。 1 つ目はコンパイル用です。これにより、パッケージ コンシューマーのコードはアセンブリ内の API に対してコンパイルされ、Intellisense は提案を提供できます。 2 つ目はランタイムで、アセンブリは bin ディレクトリにコピーされ、プログラムの実行中に使用されます。 一部のパッケージ作成者は、コンパイル時にパッケージ コンシューマーが使用できる独自のアセンブリ (またはアセンブリのサブセット) のみを希望しますが、すべての依存関係をランタイムに提供する必要があります。 このドキュメントでは、この結果を実現する方法について説明します。
推奨: パッケージごとに 1 つのアセンブリ
アセンブリごとに 1 つのパッケージを用意し、他のアセンブリへの依存関係をパッケージ化することをお勧めします。 NuGet は、プロジェクトを復元すると、アセットの選択を行い、プライベートな異なるアセット クラスを含める(除外する)、作成をサポートします。 パッケージの依存関係がパッケージを使用するすべてのユーザーのコンパイル時アセットにならないように、 compile アセットをプライベートにすることができます。 生成されたパッケージでは、依存関係から compile が除外されます。 何も指定されていない場合の既定のプライベート資産は contentfiles;build;analyzersされることに注意してください。 そのため、PrivateAssets="compile;contentfiles;build;analyzers"またはPackageReferenceでProjectReferenceを使用する必要があります。
<ItemGroup>
<ProjectReference Include="..\OtherProject\OtherProject.csproj" PrivateAssets="compile;contentfiles;build;analyzers" />
<PackageReference Include="SomePackage" Version="1.2.3" PrivateAssets="compile;contentfiles;build;analyzers" />
</ItemGroup>
NuGet で自動生成するのではなく、カスタム nuspec ファイルからパッケージを作成する場合は、 nuspec で exclude XML 属性を使用する必要があります。
<dependencies>
<group targetFramework=".NETFramework4.8">
<dependency id="OtherProject" version="3.2.1" exclude="Compile,Build,Analyzers" />
<dependency id="SomePackage" version="1.2.3" exclude="Compile,Build,Analyzers" />
</group>
</dependencies>
これが推奨される解決策である理由は 3 つあります。
まず、便利なアセンブリは、多くの場合、新しいアセンブリ/パッケージによって参照されます。 ユーティリティ アセンブリは現在、1 つのパッケージでのみ使用することを意図している可能性があるため、両方のアセンブリを 1 つのパッケージに発送したいと思うかもしれませんが、2 つ目のパッケージで将来 "プライベート" ユーティリティ アセンブリを使用する場合は、ユーティリティ アセンブリを新しいパッケージに移動し、古いパッケージを更新して依存関係として宣言する必要があります。 またはユーティリティ パッケージは、既存のパッケージと新しいパッケージの両方に発送する必要があります。 アセンブリが 2 つの異なるパッケージに含まれており、プロジェクトが両方のパッケージを参照している場合、2 つのパッケージに異なるバージョンのユーティリティ アセンブリがある場合、NuGet はバージョン管理を支援できません。
第 2 に、パッケージを使用する開発者が依存関係の API も使用したい場合があります。 たとえば、 パッケージ Microsoft.ServiceHub.Client バージョン 3.0.3078 を考えてみましょう。 パッケージをダウンロードして nuspec ファイルを確認すると、依存関係として Microsoft.VisualStudio. で始まる 2 つのパッケージが一覧表示されます。つまり、実行時に必要になりますが、コンパイルアセットも除外されます。 つまり、Microsoft.ServiceHub.Client を使用するプロジェクトでは、プロジェクトが明示的にそれらのパッケージをインストールしない限り、IntelliSense では Visual Studio API が利用できず、またプロジェクトをビルドする際にもそれらの API は使用できません。 また、これは、除外資産を持つパッケージの依存関係が持つ利点です。 パッケージを使用するプロジェクトでも依存関係を使用する場合は、パッケージへの参照を追加して、API を自分で使用できるようにします。
最後に、パッケージの作成者の中には、複数のターゲット フレームワークをサポートするパッケージに対する NuGet のアセンブリの選択について、パッケージに複数のアセンブリが含まれているとき、以前は混乱していたものもあります。 メイン アセンブリがユーティリティ アセンブリに対して異なるターゲット フレームワークをサポートしている場合、すべてのアセンブリをどの lib/ ディレクトリに配置するかは明らかでない可能性があります。 各パッケージをアセンブリ名ごとに分けることで、各アセンブリがどのフォルダーに入るべきかがより直感的に理解できるようになります。 これは、Package1.net48 パッケージと Package1.net6.0 パッケージを持っていることを意味するものではありません。 これは、lib/net48/Package1.dllにlib/net6.0/Package6.0とPackage1を持ち、lib/netstandard2.0/Package2.dllでlib/net5.0/Package2.dllとPackage2を持つことを意味します。 Nuget がプロジェクトを復元すると、Nuget は 2 つのパッケージのアセット選択を個別に行います。
また、依存関係のインクルード/除外アセットは、PackageReference を使用するプロジェクトでのみ使用されることに注意してください。
packages.configを使用してパッケージをインストールするプロジェクトでは、依存関係がインストールされ、その API も使用できるようになります。
packages.config は、Visual Studio の以前の .NET Framework プロジェクト テンプレートでのみサポートされています。 .NET Framework を対象とする SDK スタイル プロジェクトでも、 packages.configはサポートされていないため、依存関係のインクルード/除外アセットがサポートされます。
推奨されない: 1 つのパッケージ内の複数のアセンブリ
PackageReference
packages.configにはさまざまな機能があります。
PackageReference、packages.config、またはその両方を使用するパッケージ コンシューマーをサポートする場合でも、パッケージを作成する方法が変わります。
NuGet の MSBuild Pack ターゲットでは、プロジェクト参照をパッケージに自動的に含めることはできない。 参照されているプロジェクトのみがパッケージの依存関係として一覧表示されます。
GitHub には問題があり、コミュニティ メンバーがこの結果を達成する方法を共有しました。通常、パッケージにPackagePathめる方法に関するドキュメントで説明されているように、msBuild 項目メタデータ使用してパッケージ内の任意の場所にファイルを配置し、プロジェクト参照がパッケージの依存関係になるのを回避するためにSuppressDependenciesWhenPackingを使用する必要があります。 また、この機能をサポートする NuGet の公式パックの代わりに使用できる、コミュニティで開発されたツールもあります。
PackageReference サポート
パッケージ コンシューマーが PackageReferenceを使用する場合、NuGet は前述のようにコンパイルアセットとランタイムアセットを個別に選択します。
コンパイルアセットは ref/<tfm>/*.dll ( ref/net6.0/*.dllなど) を優先しますが、存在しない場合は lib/<tfm>/*.dll にフォールバックします (たとえば、 lib/net6.0/*.dll)。
ランタイム資産は runtimes/<rid>/lib/<tfm>/*.dll (たとえば (runtimes/win11-x64/lib/net6.0/*.dll)) を優先しますが、存在しない場合は、 lib/<tfm>/*.dllにフォールバックします。
ref\<tfm>\内のアセンブリは実行時に使用されないため、パッケージ サイズを小さくするためにメタデータのみのアセンブリである可能性があります。
packages.config サポート
packages.configを使用して NuGet パッケージを管理するプロジェクトでは、通常、lib\<tfm>\ ディレクトリ内のすべてのアセンブリへの参照が追加されます。
ref\ ディレクトリはPackageReferenceをサポートするために追加されたため、packages.configを使用する場合は考慮されません。
packages.configを使用してプロジェクトで参照するアセンブリを明示的に設定するには、パッケージで nuspec ファイル内の <references> 要素を使用する必要があります。 例えば次が挙げられます。
<references>
<group targetFramework="net45">
<reference file="MyLibrary.dll" />
</group>
</references>
MSBuild パック ターゲットは、 <references> 要素をサポートしていません。 MSBuild パック を使用する場合は、.nuspec ファイルを使用したパッキングに関するドキュメント を参照してください。
注
packages.config プロジェクトでは、 ResolveAssemblyReference というプロセスを使用して、アセンブリを bin\<configuration>\ 出力ディレクトリにコピーします。 プロジェクトのアセンブリがコピーされた後、ビルド システムは参照されるアセンブリのアセンブリ マニフェストを調べて、それらのアセンブリをコピーし、すべてのアセンブリに対して再帰的に繰り返します。 つまり、リフレクション (Assembly.Load、MEF、またはその他の依存関係挿入フレームワーク) によってのみ読み込まれたアセンブリがある場合、bin\<configuration>\に存在していても、プロジェクトのbin\<tfm>\出力ディレクトリにコピーされない可能性があります。 これは、P/Invoke で呼び出されるネイティブ コードに対しては機能せず、.NET アセンブリでのみ機能することを意味します。
PackageReferenceおよびpackages.configのサポート
Important
パッケージに nuspec <references> 要素が含まれており、 ref\<tfm>\にアセンブリが含まれていない場合、NuGet は、コンパイルアセットとランタイムアセットの両方として nuspec <references> 要素にリストされているアセンブリをアドバタイズします。 つまり、参照されるアセンブリが lib\<tfm>\ ディレクトリ内の他のアセンブリを読み込む必要がある場合は、ランタイム例外が発生します。 そのため、<references>サポートには nuspec packages.configを使用し、ref/サポートのために PackageReference フォルダーにアセンブリを複製することが重要です。
runtimes/ パッケージ フォルダーを使用する必要はありません。完全にするために上記のセクションに追加されました。
Example
パッケージには、.NET Framework 4.7.2 を対象とする 3 つのアセンブリ ( MyLib.dll、 MyHelpers.dll 、 MyUtilities.dll) が含まれます。
MyUtilities.dll には、他の 2 つのアセンブリでのみ使用されることを意図したクラスが含まれているため、これらのクラスを IntelliSense またはコンパイル時にパッケージを使用してプロジェクトで使用できるようにしたくありません。
nuspec ファイルには、次の XML 要素が含まれている必要があります。
<references>
<group targetFramework="net472">
<reference file="MyLib.dll" />
<reference file="MyHelpers.dll" />
</group>
</references>
パッケージの内容が次のものであることを確認する必要があります。
lib\net472\MyLib.dll
lib\net472\MyHelpers.dll
lib\net472\MyUtilities.dll
ref\net472\MyLib.dll
ref\net472\MyHelpers.dll