従来形式のC#プロジェクトで、nugetパッケージの参照方法をpackages.configからPackageReferenceに変更しました。
C#プロジェクトでnugetパッケージの参照
Visual Studioの従来形式C#プロジェクトで、nugetパッケージを参照すると、packages.configファイルにパッケージ情報が記録されます。
SDKスタイル形式のC#プロジェクトでは、nugetパッケージを参照すると、プロジェクトファイル内にPackageReferenceとしてパッケージ情報が記録されます。
このように、同じC#プロジェクトでであっても、プロジェクトファイルの形式によってnugetパッケージ情報の記録される場所が異なります。
と、つい最近まで、私はこのように理解していました。
従来形式のC#プロジェクトでPackageReferenceが利用可能
ところが、最近、新しい発見がありました。従来形式のC#プロジェクトをVisual Studio 2019で開いて、なにげなしに、ソリューションエクスプローラー内のpackages.configファイルをマウスの右ボタンでクリックし、コンテキストメニューを開きました。すると以下のようなコンテキストメニューが表示されます。
「packages.config を PackageReference に移行する」というメニュー項目があります。従来形式のC#プロジェクトでも、PackageReferenceが使えたのです。
念のため、Visual Studio 2017とVisual Studio 2015でも同様の確認をしました。
上記のように、Visual Studio 2017にも移行メニューは存在しました。しかし、Visual Studio 2015には、移行メニューはありませんでした。結果として私が知らなかっただけで、従来形式のC#プロジェクトでも、Visual Studio 2017以降ではPackageReferenceが利用可能だったのです。
packages.configとPackageReferenceのnugetパッケージ参照の違い
では、packages.configによるnugetパッケージ参照とPackageReferenceによるnugetパッケージ参照とでは何が異なるのでしょうか?
利点に関しては、パッケージ参照の情報がシンプルになるということにつきます。
packages.configの場合
packages.configでは、nugetパッケージを参照した場合、参照設定をした時にすべての情報(パッケージ情報、パッケージの依存関係、ターゲットフレームワークのバージョンなど)が解決されます。
そのため、
- 直接参照したnugetパッケージ
- 直接参照したnugetパッケージが参照しているnugetパッケージ(子パッケージへの参照)
- 直接参照したnugetパッケージが参照しているnugetパッケージ(子)が参照しているnugetパッケージ(孫パッケージへの参照)
- …
のように、子パッケージや孫パッケージまですべて展開してpackages.configファイルに情報が記載されます。そのため、後からpackage.configをみても、どれが直接参照したnugetパッケージなのかわからなくなります。
また、packages.configに記載されるのは使用しているパッケージ情報だけであり、実際の参照設定は、プロジェクトファイル側にReferenceとして情報が記載されます。
例を挙げるなら、以下のような感じです。
まず、packages.configですが、下記のようにパッケージIDとバージョン情報、ターゲットフレームワークのバージョン情報が記載されています。
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Extended.Wpf.Toolkit" version="3.2.0" targetFramework="net45" />
<package id="Microsoft.ApplicationInsights" version="1.2.3" targetFramework="net461" />
<package id="Microsoft.ApplicationInsights.PersistenceChannel" version="1.2.3" targetFramework="net45" />
</packages>
そして、プロジェクトファイル側では以下のように、通常のdllファイルへの参照と同じように、すべてのモジュールに対してReferenceタグで情報が記載されます。
<ItemGroup>
<Reference Include="Microsoft.ApplicationInsights, Version=1.2.3.490, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ApplicationInsights.1.2.3\lib\net45\Microsoft.ApplicationInsights.dll</HintPath>
</Reference>
<Reference Include="Microsoft.ApplicationInsights.PersistenceChannel, Version=1.2.3.490, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.ApplicationInsights.PersistenceChannel.1.2.3\lib\net45\Microsoft.ApplicationInsights.PersistenceChannel.dll</HintPath>
</Reference>
<Reference Include="Xceed.Wpf.Toolkit, Version=3.2.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Extended.Wpf.Toolkit.3.2.0\lib\net40\Xceed.Wpf.Toolkit.dll</HintPath>
</Reference>
</ItemGroup>
この方式の問題点は、
- 直接参照したパッケージパッケージがわからなくなる
- パッケージのバージョンを変更するとき、両方のファイルの情報を同時に変更する必要があること
- ターゲットフレームワークのバージョンを変更するとき、両方のファイルの情報を同時に変更する必要があること
などです。
PackageReferenceの場合
packages.configによる方式に対し、PackageReferenceタグによる方式の場合は、packages.configファイルは必要とせず、情報はプロジェクトファイルのみに記載されます。
記載される情報は、
- 直接参照したパッケージの情報(IDとバージョンのみ)
となります。ターゲットフレームワークのバージョンや依存するパッケージなどは、nugetパッケージ情報を使ってプロジェクトのビルド時に自動的に解決されます。
そのため、とてもシンプルな記載となります。
例を挙げるなら、以下のような感じです。
packages.config方式の例と同じ参照をした場合の例です。下記のようにパッケージIDとバージョン情報のみが記載されています。また、直接参照したパッケージパッケージ以外の情報は記載されていません。ターゲットフレームワークのバージョンのバージョンは、プロジェクトの設定に連動しているため、PackageReferenceタグの情報としては記載がありません。
<ItemGroup>
<PackageReference Include="Extended.Wpf.Toolkit">
<Version>3.2.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.ApplicationInsights.PersistenceChannel">
<Version>1.2.3</Version>
</PackageReference>
</ItemGroup>
packages.config方式の例と比べてみるとわかりますが、とてもシンプルな記述となっています。
また、packages.config方式の欠点として先に挙げた項目はすべて解決しています。
packages.config方式をPackageReference方式にマイグレーション
従来形式のC#プロジェクトではPackageReference方式は使えないというのは、私の思い込みでした。また、PackageReference方式はpackages.config方式よりも後に用意された方式のため、便利性があがっています。であれば、既存のC#のプロジェクトもPackageReference方式に移行(マイグレーション)したくなります。
方法は簡単です。
ソリューションエクスプローラー上のpackages.configファイルのコンテキストメニューを開き、「移行する」を選択するだけです。
メニュー項目を実行すると、パッケージの依存関係を自動的に解析して、直接参照していたパッケージ(最上位パッケージ)が推定されます。
そして、上記のように直接参照しているパッケージ(最上位パッケージ)について確認がされます。もし、最上位パッケージが足りなければ、最上位パッケージとして追加したいものにチェックします。
「OK」ボタンをクリックすると、下記のように移行が開始されます。
移行が完了すると、移行結果がWEBブラウザーに英語で表示されます。
ほとんどの場合、packages.config方式からPackageReference方式への移行は、何も問題が発生せず完了します。
今回の投稿では、
- 従来形式のC#プロジェクトでPackageReference方式が利用できること
- 実際の移行方法
を紹介しました。
とても便利なPackageReference方式ですが、packages.config方式と比べいくつかの制限事項はあるようです。制限事項については、別の機会に紹介したいと思います。
“nugetパッケージの参照 #1 packages.configからPackageReferenceに変更” への1件の返信