C#による.NET Core入門(6)
.NET CoreライブラリプロジェクトをパッケージングしてNuGetサーバーに発行する
クロスプラットフォームで開発できる.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ではサポートされていない。そのため、受け取った文字列を加工して返送するメソッドなどを追加するようにしよう)。
$ 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
|
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard1.0</TargetFrameworks>
</PropertyGroup>
</Project>
|
NuGetパッケージをビルドするには、プロジェクトファイルのあるディレクトリをカレントディレクトリとして、dotnet pack
コマンドを利用する。リリースビルド構成でビルドした結果をパッケージに含める場合は、リスト3のように-c
オプションでRelease
ビルド構成を指定する。
$ dotnet pack -c Release
|
さて、これだけで簡単にNuGetパッケージ(Releaseフォルダー内のExample4.Lib.nupkgファイル)を生成できたが、パッケージ作成者の情報やバージョンなどがデフォルトのままとなっている。.NET CoreのプロジェクトでNuGetパッケージに指定する情報は、.csprojファイルで指定できる。全ての設定は公式ドキュメントで参照できるが、一例をリスト4に示す。
<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>
|
NuGetに固有の設定もあれば、NuGetを使用しない場合でも利用する共有の設定もある。<TargetFrameworks>
や<Version>
などが共有の設定である。
また、デフォルトのコマンドオプションでは、ソースコードのみのビルド結果を含んだパッケージが生成され、シンボル(.pdb
ファイル)を含むシンボルパッケージは生成されない。シンボルファイルはデバッグ時に参照すると行番号など有益な情報を提供できる半面、リバースエンジニアリングが容易になる懸念もある。そのような懸念が問題ない場合は、利用しやすくするために、ぜひシンボルを含んだパッケージも生成して公開してほしい。
シンボル用のパッケージも生成するためには--include-symbols
オプションを追加指定する。実行結果の例を図1に示す。
バージョンの指定
パッケージのバージョニングについて少し説明したい。
NuGetパッケージのバージョンはセマンティックバージョニングを採用しており、X.Y.Z
という形式となっている。X/Y /Zは0以上の整数値で、Xがメジャー、Yがマイナー、Zがパッチを意味し、Xが大きい方がより新しく、Xが同じであればYがより大きい方、XとYが同じ場合は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部分をまず指定する。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
……省略……
<!--<Version>1.0.0</Version>-->
<VersionPrefix>0.1.0</VersionPrefix>
……省略……
</PropertyGroup>
</Project>
|
そして、donet pack
コマンドの--version-suffix
オプションでSuffix(例えば--version-suffix "ci-123"
)を指定すればよい。実行例を図2に示す。
NuGetパッケージの公開
nuget.orgのアカウント生成とログイン
nuget.orgはパッケージを公開するためにはアカウントの登録が必要となる。
nuget.orgにアクセスして、右上の[Sign in]リンクをクリックしよう(図3)。Microsoftアカウントでのログインもしくは、nuget.orgでのアカウント作成の2通りが選べるが、今回はMicrosoftアカウントでログインした。なお、いわゆるMicrosoftの個人アカウントのみで利用でき、学校または組織のアカウント(独自ドメインで管理されているアカウント)では利用できない。
新規のMicrosoftアカウントでログインした場合、「既存のnuget.orgアカウントと関連付けるか、新規に作成するか」を聞かれるので、既存のアカウントを持っていなければ新規にアカウントを作成しよう。ユーザー名を登録すると完了だ。
この例ではメールアドレスがoutlook.jpドメインになっているが、個人のMicrosoftアカウントで利用可能なアドレスであればどのドメインでも問題ない。
登録後、登録したEメールアドレスにアカウント確認のメールが送信されるので、メールに記載されているリンクをクリックしておこう。
その後、コマンドラインからnuget
パッケージを公開するためのAPIキーを発行しよう。これには、nuget.orgにログインした状態で右上のアカウント名のドロップダウンメニューより[API Keys]を選択する。図4の画面のようにして、必要な項目を入力してキーを作成しよう。
- キーの名前(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に関しては公開後に編集することも可能だ。
最後に、マニフェストの内容を確認して公開できる。
公開すると、nuget.orgの該当パッケージは図6のように表示される。Unlist状態であるのでメッセージが表示されており、Unlistなパッケージは、nuget.orgやVisual Studio Code、Visual Studioなどの検索結果には表示されない。しかし、nuget.orgのパッケージのURLを直接開けば表示され、パッケージ名を指定すればプロジェクトに追加することもできる。
なお、listされる設定で公開した場合や、Unlistからlistに設定を変更した場合、インデクシングされて検索結果に表示されるようになるまでには、ある程度の時間が必要であるので注意してほしい。
コマンドラインを使ったNuGetパッケージの公開
コマンドラインからアップロードする場合は、APIキーが必要だが、シンボルソースも同時にアップロードできる。
dotnet nuget publish
コマンドで、-k
オプションでAPIキーを、-s
もしくは--source
オプションでNuGetホストサーバーを、-ss
もしくは--symbol-source
オプションでシンボルソースを指定する。より詳細なコマンドオプションについては公式ドキュメントを参照してほしい。
また、コマンドラインではUnlistした状態での公開ではできないので、Unlistする必要があればdonet nuget delete
コマンドを実行する。図7がパッケージ公開のコマンド実行例である。
プロジェクト参照からNuGet参照への変更
前回の連載でプロジェクト参照している部分を、アップロードしたNuGetパッケージへの参照に変えてみよう。
コマンドラインでは、donet remove reference
とdotnet add package
を使い、対象の.csprojファイルからプロジェクト参照を削除し、代わりにアップロードしたNuGetパッケージを追加すればよい。
また、連載第3回で説明した通り、dotnet add package
は.csprojファイルに追加するだけで、実体のNuGetパッケージはダウンロードされていないので、その後でdotnet restore
コマンドの実行、もしくはVisual Studio Code上のメッセージに従いパッケージの復元処理が必要である。
図8が実際にコマンドを実行した様子である。
また、donet remove reference
とdotnet add package
のコマンドは.csprojファイルを編集するだけなので、実行前のリスト6の.csprojファイルを実行後のリスト7のように直接編集しても構わない。
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\Example4.Lib\Example4.Lib.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
</Project>
|
<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>
|
この例では
要素の位置が変わっているが、手動で直接編集する場合には、このように位置変えする必要はなく、単に
要素の中身を書き換えればよい。
nuget.org以外のNuGetホスト
nuget.org以外のNuGetホストを使う理由はいくつかある。具体的には、nuget.orgはデフォルトで参照可能であるため、実験的なパッケージなど意図的に追加した場合のみ参照してほしい場合や、パッケージの削除をサポートしてほしい場合、特定の人以外から参照されたくないため認証を必須としたい場合、プライベートネットワーク以外からアクセスされたくない場合、などがある。
NuGetのドキュメントでも紹介されているが、ここでもいくつかnuget.org以外のNuGetホストを紹介しておこう。なお、いずれのNuGetホストについても公開する場合の手順は、図7のようにコマンドラインを使う場合は同じである。それぞれのNuGetホストごとにAPIキーを作る手順が用意されているので、APIキーを作成し、NuGetホストのURLと合わせて指定すればよい。
Visual Studio Team Services(VSTS)やAppVeyorの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]を参照してください。
3. .NET Coreでプロジェクトを作成して開発してみよう
クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。3回目は実際にプロジェクトを新規に作成して、Visual Studio Codeを使って開発するフローを説明する。
4. .NET Coreでコンソールアプリを配置する
クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。4回目は作成したコンソールアプリのプロジェクトをビルドして配置する手順を説明する。
5. .NET Standardなライブラリプロジェクトを作成して参照する
クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。5回目は.NET Standardなクラスライブラリなプロジェクトを作成し、別のコンソールプロジェクトから参照する方法を説明する。
6. 【現在、表示中】≫ .NET CoreライブラリプロジェクトをパッケージングしてNuGetサーバーに発行する
クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。6回目はクラスライブラリプロジェクトをNuGetパッケージとして参照できるように、作成と発行を行う。
7. .NET Coreで単体テストを行う
クロスプラットフォームで開発できる.NET Coreの基礎から開発実践までが学べる入門連載。最終回は単体テスト用のプロジェクトを作成して、テストを行う方法を説明する。