C#による.NET Core入門(6)

C#による.NET Core入門(6)

.NET CoreライブラリプロジェクトをパッケージングしてNuGetサーバーに発行する

2018年2月6日

クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。6回目はクラスライブラリプロジェクトをNuGetパッケージとして参照できるように、作成と発行を行う。

レッドハット株式会社 田中 孝佳
  • このエントリーをはてなブックマークに追加

NuGetパッケージとnuget.org

NuGetパッケージ

 前回はクラスライブラリプロジェクトをプロジェクト参照として別のプロジェクトから参照した。プロジェクト参照の場合、ソースコードを直接参照するため、ソースコードが必要であり、ビルドのたびにライブラリ側のビルドも行われる。ビルド後のバイナリのみを参照したい場合、ビルド成果物である.dllファイルのみを参照するという方法があるが、.dllファイルのみを参照すると、クラスライブラリ自身のバージョンや、クラスライブラリが必要とする別のライブラリのバージョンの管理を手動で行う必要がでてくる。

 そこでNuGetパッケージとしてパッケージングすることで、それらの管理をNuGetに任せることができる。今回はクラスライブラリプロジェクトをNuGetパッケージとして出力し、公開する手順を説明したい。

 NuGetパッケージを作成する前に、NuGetパッケージの構造について簡単に説明しよう。

 NuGetパッケージは.nupkgという拡張子を持ったファイルであるが、実体はZIP圧縮されたファイルである。ライブラリ本体である.dllファイルの他に、バージョンや著作者、依存関係などの情報を記述したマニフェストファイルや、インストール時に実行可能なスクリプト、プロジェクトに追加するファイルなどを含めることができる。

 前回説明した.NET Standardを利用すると、例えば.NET Standard 2.0でビルドした単一のバイナリを提供することで、.NET Standard 2.0がサポートしている全てのプラットフォームに対応したパッケージとすることができる。さらに、複数のターゲットプラットフォームでビルドしたバイナリを同一のパッケージに含めることができるため、.NET Standard 2.0・.NET Standard 1.0・.NET Framework 4以下といったさまざまなプラットフォームに対応した単一のNuGetパッケージも作成できる。

nuget.orgとその他のホスティング

 NuGetパッケージをファイルシステム上に配置することでも、.NET Coreコマンドラインツールは、そのNuGetパッケージを検索してプロジェクトに追加することができる。しかし一般的には、より広く安全に検索、参照できるようにするため、Webサイトにホストして提供されている。その一つがマイクロソフトからの公式パッケージもホストしているnuget.orgである。

 nuget.orgはアカウント登録すれば一般の開発者もパッケージを無料でホストでき、.NET Core SDKやVisual Studioなどほとんどのツールにおいてデフォルトで利用可能になっている。今回は、作成したNuGetパッケージをnuget.orgに公開する手順も説明する。

 一方、nuget.org以外のサイトでNuGetパッケージをホストすることも可能であるので、最後の節で説明する。

NuGetパッケージの作成

 それでは前回作成したExample4.Libプロジェクトを対象にNuGetパッケージを作成してみよう。

 今回試すのに必要な前回の手順を再度リスト1とリスト2に載せた。この手順だけでは参照可能なメソッドが存在しないので、必要であれば前回のコードを参考に追加してほしい(ただし、ここでは.NET Standard 1.0/2.0に対応するクラスライブラリを作成する。このとき、前回に使用したstringクラスのCopyメソッドが.NET Standard 1.0ではサポートされていない。そのため、受け取った文字列を加工して返送するメソッドなどを追加するようにしよう)。

shell
$ mkdir Example4
$ cd Example4
$ dotnet new sln
$ dotnet new console -o Example4.ConsoleApp
$ dotnet sln add Example4.ConsoleApp/Example4.ConsoleApp.csproj
$ dotnet new classlib -o Example4.Lib
$ dotnet sln add Example4.Lib/Example4.Lib.csproj
リスト1 ソリューションとクラスライブラリとコンソールプロジェクトを作成し、プロジェクトをソリューションに追加するコマンド
Example4.Lib.csproj
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;netstandard1.0</TargetFrameworks>
  </PropertyGroup>
</Project>
リスト2 ターゲットを追加したクラスライブラリの.csprojファイル

 NuGetパッケージをビルドするには、プロジェクトファイルのあるディレクトリをカレントディレクトリとして、dotnet packコマンドを利用する。リリースビルド構成でビルドした結果をパッケージに含める場合は、リスト3のように-cオプションでReleaseビルド構成を指定する。

shell
 $ dotnet pack -c Release
リスト3 NuGetパッケージを生成するコマンド

 さて、これだけで簡単にNuGetパッケージ(Releaseフォルダー内のExample4.Lib.nupkgファイル)を生成できたが、パッケージ作成者の情報やバージョンなどがデフォルトのままとなっている。.NET CoreのプロジェクトでNuGetパッケージに指定する情報は、.csprojファイルで指定できる。全ての設定は公式ドキュメントで参照できるが、一例をリスト4に示す。

XML
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;netstandard1.0</TargetFrameworks>
    <Version>1.0.0</Version>
    <PackageId>MyPackage.tanaka733</PackageId>
    <Title>My Awesome Library</Title>
    <Authors>tanaka_733</Authors>
    <Description>Example test packge.</Description>
    <Copyright>None.</Copyright>
    <PackageLicenseUrl>https://opensource.org/licenses/MIT</PackageLicenseUrl>
    <PackageProjectUrl>https://github.com/tanaka-takayoshi</PackageProjectUrl>
    <PackageReleaseNotes>This is an example release.</PackageReleaseNotes>
  </PropertyGroup>
</Project>
リスト4 NuGetパッケージに関する設定を追加した.csprojファイル

 NuGetに固有の設定もあれば、NuGetを使用しない場合でも利用する共有の設定もある。<TargetFrameworks><Version>などが共有の設定である。

 また、デフォルトのコマンドオプションでは、ソースコードのみのビルド結果を含んだパッケージが生成され、シンボル(.pdbファイル)を含むシンボルパッケージは生成されない。シンボルファイルはデバッグ時に参照すると行番号など有益な情報を提供できる半面、リバースエンジニアリングが容易になる懸念もある。そのような懸念が問題ない場合は、利用しやすくするために、ぜひシンボルを含んだパッケージも生成して公開してほしい。

 シンボル用のパッケージも生成するためには--include-symbolsオプションを追加指定する。実行結果の例を図1に示す。

図1 dotnet packコマンドによる.nupkgファイルの生成例

バージョンの指定

 パッケージのバージョニングについて少し説明したい。

 NuGetパッケージのバージョンはセマンティックバージョニングを採用しており、X.Y.Zという形式となっている。XYZは0以上の整数値で、Xがメジャー、Yがマイナー、Zがパッチを意味し、Xが大きい方がより新しく、Xが同じであればYがより大きい方、XYが同じ場合はZがより大きい方がより新しいバージョンとなる。

 また「プレビューバージョン」という概念があり、これはX.Y.Z-sという形式で-(ハイフン)が必須で、sは1文字以上の半角英数およびハイフンである。なお、NuGet 4.3.0以降では.(ピリオド)を利用することもできる。-s が付いたバージョンは全てプレビューバージョンであり、正式版のX.Y.(Z-1)よりは新しいが、X.Y.Zよりは古いという扱いとなる。複数のプレビューバージョンの順序はアルファベットの逆順となり、例えばzzz、rc1、beta3、beta1、alph34の順に新しいバージョンとなる。

 デフォルトではプロジェクトの<Version>値がパッケージのバージョンとなる。正式にリリースするバージョンのみをビルドすることを考えると、リリースが決定した後でバージョン値を書き換え、NuGetパッケージを生成し、必要があればそのバージョンでバージョン管理システムにバージョン値をタグ付けすればいいだろう。

 だが、CI(継続的インテグレーション)/CD(継続的デプロイメント)を利用している環境でCI/CDのたびに異なるバージョンでインクリメントし自動でNuGetパッケージをプッシュしたい場合、ソースコードを書き換えるのをCI/CDで行うのは煩雑なこともあるだろう。そこでお勧めしたいのが、バージョンのPrefix部分(X.Y.Z)の部分を.csprojファイルで指定し、プレビュー扱いとなるSuffixの部分(-sのs)を dotnet pack時のコマンドオプションで指定する方法だ。

 この方法であれば、CI/CDの実行時にCI/CD側で日時やビルド番号といったインクリメントされるSuffixを自動で指定するようにすると、常に新しいプレビューバージョンのパッケージを生成できる。リリース時にはこのオプションを指定せずにパッケージを生成すればよい。

 この方法を利用するのは簡単だ。.csprojファイルの<Version>の代わりに<VersionPrefix>でPrefix部分をまず指定する。

XML
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    ……省略……
    <!--<Version>1.0.0</Version>-->
    <VersionPrefix>0.1.0</VersionPrefix>
    ……省略……
  </PropertyGroup>
</Project>
リスト5 Versionの代わりにVersionPrefixを.csprojで指定する例。それ以外の要素は省略

 そして、donet packコマンドの--version-suffixオプションでSuffix(例えば--version-suffix "ci-123")を指定すればよい。実行例を図2に示す。

図2 --version-suffixオプションを指定してプレビューバージョンのパッケージを生成する例

NuGetパッケージの公開

nuget.orgのアカウント生成とログイン

 nuget.orgはパッケージを公開するためにはアカウントの登録が必要となる。

 nuget.orgにアクセスして、右上の[Sign in]リンクをクリックしよう(図3)。Microsoftアカウントでのログインもしくは、nuget.orgでのアカウント作成の2通りが選べるが、今回はMicrosoftアカウントでログインした。なお、いわゆるMicrosoftの個人アカウントのみで利用でき、学校または組織のアカウント(独自ドメインで管理されているアカウント)では利用できない。

 新規のMicrosoftアカウントでログインした場合、「既存のnuget.orgアカウントと関連付けるか、新規に作成するか」を聞かれるので、既存のアカウントを持っていなければ新規にアカウントを作成しよう。ユーザー名を登録すると完了だ。

[Sign in]リンクをクリック。今回はMicrosoftアカウントでログイン

[Sign in]リンクをクリック。今回はMicrosoftアカウントでログイン

「既存のnuget.orgアカウントと関連付けるか、新規に作成するか」を聞かれたので、今回は新規に作成する方を選択

「既存のnuget.orgアカウントと関連付けるか、新規に作成するか」を聞かれたので、
今回は新規に作成する方を選択

[Register]ボタンをクリックすると、Microsoftアカウントと関連付けられたnuget.orgアカウントが新規作成される

[Register]ボタンをクリックすると、
Microsoftアカウントと関連付けられたnuget.orgアカウントが新規作成される

図3 nuget.orgにMicrosoftアカウントでログインして、新規のnuget.orgアカウントと関連付ける様子

この例ではメールアドレスがoutlook.jpドメインになっているが、個人のMicrosoftアカウントで利用可能なアドレスであればどのドメインでも問題ない。

 登録後、登録したEメールアドレスにアカウント確認のメールが送信されるので、メールに記載されているリンクをクリックしておこう。

 その後、コマンドラインからnugetパッケージを公開するためのAPIキーを発行しよう。これには、nuget.orgにログインした状態で右上のアカウント名のドロップダウンメニューより[API Keys]を選択する。図4の画面のようにして、必要な項目を入力してキーを作成しよう。

図4 NuGet APIキーの作成画面
  • キーの名前(Key Name): 必須なので分かりやすい名前を入力する。
  • キーの有効期間(Expires In): テスト目的であれば、不正利用されないようにできるだけ短い方がいいだろう。
  • スコープの選択(Select Scopes): 必要に応じてできるだけ限定されたスコープがよい。
    • [Push new packages and package versions]」 新規のパッケージを公開できる権限。
    • [Push only new package versions]: 既存のパッケージの新しいバージョンのみ公開できる権限である。
    • [Unlist package]: この後で説明するが、パッケージを表示しなくなる(ダウンロードはできる)設定を行う権限である。
  • パッケージの選択(Select Packages): APIキーごとに公開できるパッケージを指定できる。CIサーバーなどから自動で公開するようにしているとき、このAPIキーをCIサーバーに保存する必要がある。このような場合に、誤って他のパッケージの操作を行わないようにする意味で、パッケージごとにAPIキーを分けておくことができる。

シンボルソースリポジトリ

 先ほどNuGetパッケージを作成する際に、シンボル用のパッケージを作成した。シンボル用のNuGetパッケージは、nuget.orgとは別のパブリックなシンボルソースリポジトリhttps://nuget.smbsrc.netで公開できる。このシンボルソースリソースには、nuget.orgと同一のAPIキーでアップロードできる。

 詳細に関してはNuGetの公式ドキュメントにも記載があるが、日本語版のドキュメントでは非推奨の古いリポジトリのURLが記載されているので注意してほしい。

nuget.orgへの公開

 それではNuGetパッケージを公開してみよう。なお、一度公開したパッケージは、Unlistという設定(前述)で検索結果に表示しないようにはできるが、削除はできない。これはいったんダウンロードして参照したプロジェクトやパッケージが以後利用できなくなるのを防ぐためである。そのため、公開する際はパスワードやAPIトークンなどの機密情報を入れたままパッケージを作成していないか注意しよう。誤って公開した場合の削除の依頼先や、著作権違反や危険なパッケージの削除依頼など、nuget.orgにおける詳細な削除のポリシーに関しては公式ドキュメントを参照してほしい。

 この「削除できない」および「同一バージョンを別パッケージで上書きできない」という仕様は、NuGetパッケージのホストにおいて推奨される設定ではあるが、絶対ではない。そのため、独自のNuGetホスティングシステムであれば削除可能にすることもできる。

 NuGetパッケージの公開は、nuget.orgのWebページもしくはdotnet nuget pushコマンドを使って行う。

Webページを使ったNuGetパッケージの公開

 Webページから行う場合はログインした状態で右上のアカウント名のドロップダウンメニューから[Upload package]を選択し、アップロードするパッケージを指定する(図5)。

 次に、[Verify]欄の一番下にある[Package Visibility]というところの[List Package in search results]チェックボックスを外すと、Unlistされた状態で公開できる。Unlistに関しては公開後に編集することも可能だ。

 最後に、マニフェストの内容を確認して公開できる。

[Brows]ボタンからアップロードするパッケージを指定する

[Brows]ボタンからアップロードするパッケージを指定する

上記のキャプチャ画像では見えないが、[Verify]-[Package Visibility]欄の[List Package in search results]チェックボックスを外す<br>

上記のキャプチャ画像では見えないが、
[Verify]-[Package Visibility]欄の[List Package in search results]チェックボックスを外す

[Verify]欄のマニフェストの内容を最終確認して、最後に[Submit]ボタンをクリックすると公開される

[Verify]欄のマニフェストの内容を最終確認して、
最後に[Submit]ボタンをクリックすると公開される

図5 WebからNuGetパッケージを公開するときの様子

 公開すると、nuget.orgの該当パッケージは図6のように表示される。Unlist状態であるのでメッセージが表示されており、Unlistなパッケージは、nuget.orgやVisual Studio Code、Visual Studioなどの検索結果には表示されない。しかし、nuget.orgのパッケージのURLを直接開けば表示され、パッケージ名を指定すればプロジェクトに追加することもできる。

 なお、listされる設定で公開した場合や、Unlistからlistに設定を変更した場合、インデクシングされて検索結果に表示されるようになるまでには、ある程度の時間が必要であるので注意してほしい。

図6 UnlistなNuGetパッケージを表示した状態
コマンドラインを使ったNuGetパッケージの公開

 コマンドラインからアップロードする場合は、APIキーが必要だが、シンボルソースも同時にアップロードできる。

 dotnet nuget publishコマンドで、-kオプションでAPIキーを、-sもしくは--sourceオプションでNuGetホストサーバーを、-ssもしくは--symbol-sourceオプションでシンボルソースを指定する。より詳細なコマンドオプションについては公式ドキュメントを参照してほしい。

 また、コマンドラインではUnlistした状態での公開ではできないので、Unlistする必要があればdonet nuget deleteコマンドを実行する。図7がパッケージ公開のコマンド実行例である。

図7 dotnet nuget pushコマンドでパッケージを公開した様子

プロジェクト参照からNuGet参照への変更

 前回の連載でプロジェクト参照している部分を、アップロードしたNuGetパッケージへの参照に変えてみよう。

 コマンドラインでは、donet remove referencedotnet add packageを使い、対象の.csprojファイルからプロジェクト参照を削除し、代わりにアップロードしたNuGetパッケージを追加すればよい。

 また、連載第3回で説明した通り、dotnet add packageは.csprojファイルに追加するだけで、実体のNuGetパッケージはダウンロードされていないので、その後でdotnet restoreコマンドの実行、もしくはVisual Studio Code上のメッセージに従いパッケージの復元処理が必要である。

 図8が実際にコマンドを実行した様子である。

図8 プロジェクト参照を削除し、NuGetパッケージ参照の追加を実行した様子

 また、donet remove referencedotnet add packageのコマンドは.csprojファイルを編集するだけなので、実行前のリスト6の.csprojファイルを実行後のリスト7のように直接編集しても構わない。

XML
<Project Sdk="Microsoft.NET.Sdk">

  <ItemGroup>
    <ProjectReference Include="..\Example4.Lib\Example4.Lib.csproj" />
  </ItemGroup>

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

</Project>
リスト6 連載5回目で作成した状態の.csprojファイル
XML
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="MyPackage.tanaka733" Version="0.1.0-ci-456" />
  </ItemGroup>

</Project>
リスト7 図8のコマンドを実行した後の.csprojファイル

この例では要素の位置が変わっているが、手動で直接編集する場合には、このように位置変えする必要はなく、単に要素の中身を書き換えればよい。

nuget.org以外のNuGetホスト

 nuget.org以外のNuGetホストを使う理由はいくつかある。具体的には、nuget.orgはデフォルトで参照可能であるため、実験的なパッケージなど意図的に追加した場合のみ参照してほしい場合や、パッケージの削除をサポートしてほしい場合、特定の人以外から参照されたくないため認証を必須としたい場合、プライベートネットワーク以外からアクセスされたくない場合、などがある。

 NuGetのドキュメントでも紹介されているが、ここでもいくつかnuget.org以外のNuGetホストを紹介しておこう。なお、いずれのNuGetホストについても公開する場合の手順は、図7のようにコマンドラインを使う場合は同じである。それぞれのNuGetホストごとにAPIキーを作る手順が用意されているので、APIキーを作成し、NuGetホストのURLと合わせて指定すればよい。

 Visual Studio Team ServicesVSTSAppVeyorのNuGetホスト機能は、CI/CD機能と連携するのに便利な機能だ。

 VSTSは認証をVSTSの認証機能(つまりAzure Active Directory)に任すことができる。

 AppVeyorはpublicなGitHubリポジトリだと無償で利用可能で、CI/CDによって生成されたパッケージを専用のNuGetホストURLでホスティングできる。開発バージョンを公開したい場合に便利な機能だ。

 MyGetはSaaS形式で利用できるNuGetホスティングで、プライベートフィードもサポートしている。プライベートフィードは有償版のみ利用可能であるが、サーバーの管理をしなくてよいというメリットがある。

 NuGetサーバーをプライベートネットワークに配置したい場合は、NuGetサーバーの機能を持つソフトウェアをインストールすることになるだろう。いくつかの製品がリストされているので比較検討してほしい。NuGetサーバーに特化した製品や、mavenリポジトリサーバーとしてのソフトウェアがNuGetサーバーもサポートした製品などがある。その中では、nexusがnexus OSSというOSSとして利用可能なソフトウェアをリリースしている。

 nexus OSSはJavaで動作するため、Linuxサーバーにインストールできる。

 いくつかのNuGet Server専用の製品はIISが動作に必要であるので、Windows Serverが必要となるケースがある。

 プライベートネットワークにNuGetサーバーを配置するのは、認証付きであっても公開したくないNuGetパッケージをホストする以外に、キャッシュとしてよりネットワーク的に近い位置にパッケージを配置するという目的や、インターネット非接続環境でのビルドを可能にする目的もある。

 前者(ネットワーク的に近い場所にサーバーを配置)は、いくつかの商用製品がサポートしている機能で、プライベートネットワークに配置したNuGetサーバーを他のNuGetサーバーのプロキシとして動作させることができる。nuget.orgなどのNuGetホストへのプロキシとして動作させることで、まだキャッシュに存在しないパッケージはNuGetホストに取得しにいくが、一度でもキャッシュされていればキャッシュから提供するようになるので、NuGetパッケージのダウンロード時間を短くできる。

 後者(インターネット非接続環境でのビルドを可能にする)は、要件により開発やビルド環境をインターネット非接続環境にしないといけない場合にNuGetパッケージを提供する目的である。.NET Coreのプロジェクトはデフォルトでも数多くのパッケージをnuget.orgからダウンロードするため、インターネット非接続環境でビルドする場合は、必要な全てのNuGetパッケージをあらかじめ別の環境でダウンロードしプライベートNuGetサーバーに追加したうえで、.NET CoreプロジェクトでそのNuGetホストを参照する必要がある。

 今回は、クラスライブラリプロジェクトのNuGetパッケージとして作成し、nuget.orgに公開した。次回は、.NET Core連載の最終回としてテストプロジェクトに関して説明したい。

※以下では、本稿の前後を合わせて5回分(第3回~第7回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

C#による.NET Core入門(6)
3. .NET Coreでプロジェクトを作成して開発してみよう

クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。3回目は実際にプロジェクトを新規に作成して、Visual Studio Codeを使って開発するフローを説明する。

C#による.NET Core入門(6)
4. .NET Coreでコンソールアプリを配置する

クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。4回目は作成したコンソールアプリのプロジェクトをビルドして配置する手順を説明する。

C#による.NET Core入門(6)
5. .NET Standardなライブラリプロジェクトを作成して参照する

クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。5回目は.NET Standardなクラスライブラリなプロジェクトを作成し、別のコンソールプロジェクトから参照する方法を説明する。

C#による.NET Core入門(6)
6. 【現在、表示中】≫ .NET CoreライブラリプロジェクトをパッケージングしてNuGetサーバーに発行する

クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。6回目はクラスライブラリプロジェクトをNuGetパッケージとして参照できるように、作成と発行を行う。

C#による.NET Core入門(6)
7. .NET Coreで単体テストを行う

クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。最終回は単体テスト用のプロジェクトを作成して、テストを行う方法を説明する。

サイトからのお知らせ

Twitterでつぶやこう!