nugetパッケージの参照 #1 packages.configからPackageReferenceに変更

従来形式の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のマイグレーションメニュー(Visual Studio 2019)

「packages.config を PackageReference に移行する」というメニュー項目があります。従来形式のC#プロジェクトでも、PackageReferenceが使えたのです。

念のため、Visual Studio 2017とVisual Studio 2015でも同様の確認をしました。

packages.configのマイグレーションメニュー(Visual Studio 2017)

上記のように、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のマイグレーションメニュー(Visual Studio 2019)

ソリューションエクスプローラー上のpackages.configファイルのコンテキストメニューを開き、「移行する」を選択するだけです。

メニュー項目を実行すると、パッケージの依存関係を自動的に解析して、直接参照していたパッケージ(最上位パッケージ)が推定されます。

移行確認画面

そして、上記のように直接参照しているパッケージ(最上位パッケージ)について確認がされます。もし、最上位パッケージが足りなければ、最上位パッケージとして追加したいものにチェックします。

「OK」ボタンをクリックすると、下記のように移行が開始されます。

packages.configからPackageReferenceへ移行中

移行が完了すると、移行結果がWEBブラウザーに英語で表示されます。

移行結果画面

ほとんどの場合、packages.config方式からPackageReference方式への移行は、何も問題が発生せず完了します。


今回の投稿では、

  • 従来形式のC#プロジェクトでPackageReference方式が利用できること
  • 実際の移行方法

を紹介しました。

とても便利なPackageReference方式ですが、packages.config方式と比べいくつかの制限事項はあるようです。制限事項については、別の機会に紹介したいと思います。

“nugetパッケージの参照 #1 packages.configからPackageReferenceに変更” への1件の返信

コメントを残す