Special Windows 10 issue 2015

Volume 30 Number 11

Visual Studio ツール - Windows 10 開発を強化する NuGet の機能

Jeff Fitz | Windows 2015

NuGet チームは、いくつか新しいツールを利用できるようにしています。ユニバーサル Windows プラットフォーム (UWP) や新しいポータブル クラス ライブラリ (PCL) をサポートするため、マイクロソフトの複数のチームが連携して、NuGet の新しいバージョンを提供しました。新しい NuGet ツールは、Visual Studio 2015 で [ツール]、[拡張機能と更新プログラム]、[更新プログラム] の順にクリックするか、NuGet の配布サイト (bit.ly/1MgNt2J、英語) からダウンロードできます。NuGet は NuGet コマンドライン ツールの新しいバージョンもリリースしていて、同じサイト (dist.nuget.org) からダウンロードできます。今回は、こうした新機能に加え、Windows 10 プロジェクトに NuGet サポートを追加するために Windows 開発者が従う必要のあるプロセスを取り上げます。

Project.Json

ASP.NET 5 以降、NuGet は project.json ファイルのサポートを導入し、直接依存することになるパッケージを明確に定義して、プロジェクトの依存関係を記述できるようにしています。ASP.NET 5 では、project.json ファイルがプロジェクト構成を定義する唯一のファイルです。ただし、NuGet 3.1 では、(DNX、UWP、Microsoft .NET Framework 4.6 をターゲットにする) ユニバーサル Windows プロジェクトや最新の PCLでこのファイルを使用して、パッケージ参照を定義できます。これに関連して、Visual Studio の [パッケージの管理] ダイアログでは、開発中のプロジェクトの種類に応じて ackages.config ファイルまたは project.json ファイルを適切に管理できるようになっています。

また、packages.config モデルから切り替えられたことで、プロジェクトで参照を "付け替える" ことができるようになり、NuGet の新しい推移的依存関係を使用できるようになります。開発者やパッケージ製作者から、プロジェクトにパッケージを追加するとき、そのパッケージが持つ依存関係によって packages.config ファイルが煩雑になるという意見が NuGet チームに寄せられました。

たとえば、NHibernate というパッケージがあり、このパッケージは lesi.Collections パッケージに依存するとします。この場合、packages.config は、NHibernate と Iesi.Collections の 2 つの参照を保持します。NHibernate を更新する場合は、Iesi.Collections も更新するべきでしょうか。逆の場合はどうでしょう。lesi.collections が更新されている場合、新しい機能をサポートするためには NHibernate も更新するべきでしょうか。結局、パッケージ参照が原因で、開発者はプロジェクトで使用するパッケージの依存関係を管理する煩雑なサイクルに陥ることになります。

NuGet の推移的依存関係機能では、パッケージ定義ファイル (nuspecs ドキュメント) でのセマンティックなバージョン管理のサポートを強化し、パッケージ参照を更新するかどうかの決定を抽象化しています。開発者は、これまで自身のパッケージがサポートする依存関係のバージョンの範囲を指定していました。NuGet がクライアントをインストールするとき、こうした依存関係により packages.config ファイル内で指定されたバージョンとの緊密な参照を追加します。さらに指定したパッケージが参照するパッケージも、自身が参照するパッケージを開発者が追加したかのようにファイルに追加します。この問題の例を図 1 に示します。

図 1 ASP.NET MVC packages.config ファイルのコンテンツ

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Antlr" version="3.4.1.9004" targetFramework="net46" />
  <package id="bootstrap" version="3.0.0" targetFramework="net46" />
  <package id="EntityFramework" version="6.1.3" targetFramework="net46" />
  <package id="jQuery" version="1.10.2" targetFramework="net46" />
  <package id="jQuery.Validation" version="1.11.1" targetFramework="net46" />
  <package id="KendoUICore" version="2015.2.624" targetFramework="net46" />
  <package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net46" />
  <package id="Microsoft.AspNet.Identity.EntityFramework"
    version="2.2.1" targetFramework="net46" />
  <package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net46" />
  <package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net46" />
  <package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net46" />
  <package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net46" />
  <package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net46" />
  <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform"
    version="1.0.0" targetFramework="net46" />
  <package id="Microsoft.jQuery.Unobtrusive.Validation"
    version="3.2.3" targetFramework="net46" />
  <package id="Microsoft.Net.Compilers"
    version="1.0.0" targetFramework="net46" developmentDependency="true" />
  <package id="Microsoft.Owin" version="3.0.1" targetFramework="net46" />
  <package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net46" />
  <package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net46" />
  <package id="Microsoft.Owin.Security.Cookies" version="3.0.1" targetFramework="net46" />
  <package id="Microsoft.Owin.Security.Facebook" version="3.0.1" targetFramework="net46" />
  <package id="Microsoft.Owin.Security.Google" version="3.0.1" targetFramework="net46" />
  <package id="Microsoft.Owin.Security.MicrosoftAccount"
    version="3.0.1" targetFramework="net46" />
  <package id="Microsoft.Owin.Security.OAuth" version="3.0.1" targetFramework="net46" />
  <package id="Microsoft.Owin.Security.Twitter" version="3.0.1" targetFramework="net46" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net46" />
  <package id="Modernizr" version="2.6.2" targetFramework="net46" />
  <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net46" />
  <package id="Owin" version="1.0" targetFramework="net46" />
  <package id="Respond" version="1.2.0" targetFramework="net46" />
  <package id="WebGrease" version="1.5.2" targetFramework="net46" />
</packages>

開発者が依存関係を自身のプロジェクトに追加するとき、実際に必要なのは Microsoft.AspNet.Mvc、Microsoft.AspNet.Identity.EntityFramework、Newtonsoft.Json、および Microsoft.Owin.Security.MicrosoftAccount のみです。他の項目は、この 4 つのパッケージが参照する無意味な情報にすぎません。それなのに、こうした項目も特定のバージョンへの強固な参照を保持するようになります。推移的依存関係機能により、こうした無意味な他のパッケージのバージョンの指定は必要なくなります。実際に自身のプロジェクトで使用する 4 つのライブラリを管理するだけになります。

NuGet クライアントはこうした他のパッケージ参照を自動的に解決および管理し、それらの参照を、プロジェクトが使用しているパッケージによって宣言される依存関係のバージョンの制約内に収めます。その結果、プロジェクト参照に関するエクスペリエンスが大幅に簡略化されます。

共通ローカル パッケージ キャッシュ

多くの場合、開発者には好みのパッケージやツールがあります。明らかに既存のプロジェクトでこうしたパッケージやツールを使用しているのに、同じワークステーションの別のプロジェクトでもこれらを使おうとすると、何回もダウンロードやインストールすることになるのはなぜでしょう。project.json が管理するプロジェクトでは、NuGet が %userprofile%\.nuget\packages フォルダーにあるグローバル パッケージのフォルダーに、使用するパッケージのコピーをダウンロードして格納します。これにより、ワークステーションで使用するディスク領域が削減されます。また、NuGet.org からパッケージを取得して既存のアイテムを入手する余分な呼び出しもなくなります。

project.json と共通ローカル パッケージ キャッシュのサポートは、NuGet 3.0 と ASP.NET 5 を使用する場合に利用でき、NuGet 3.1 からはそれ以外の種類のプロジェクトにも利用できます。

非推奨の機能

NuGet 3.1 以降、project.json を使用する際は、install.ps1/­uninstall.ps1 スクリプトの実行や /content package フォルダーでの要素の提供に関するサポートは推奨されなくなります。これらの要素を含むパッケージをインストールしても、install.ps1 ファイルが実行されたり、プロジェクトにコンテンツがコピーされることはありません。ただし、packages.config ファイルを使用しているプロジェクトでは、依然としてこの動作がサポートされます。これには以下のような理由があります。

  • パッケージが推移的に復元されることにより、アンインストール/インストールする対象を確実に選択することができないため。
  • ユーザー プロジェクトにコンテンツをコピーすると、パッケージが更新され、暗黙のアンインストール プロセスを確実に実行できないため。
  • NuGet では Visual Studio 以外の開発を完全にサポートする必要があるため。完全なクロスプラットフォームの .NET 開発エクスペリエンスに移行した場合、Windows Powershell を他の環境で利用できません。また、Visual Studio 以外で .NET コードを使って作業している開発者は多く、その対応も必要になります。
  • 他のパッケージ マネージャーがコンテンツの管理と配信に優れたエクスペリエンスを提供するため。NuGet は .NET Framework のパッケージ マネージャーとして優れた働きをするため、引き続き使用することが推奨されます。
  • すべてのフレームワークをサポートすることがなくなるため。ビルドのルートや lib フォルダーに直接ファイルを配置したり、プロジェクトにファイルを提供することはできなくなっています。ファイルがサポートするフレームワークを宣言することが重要になるため、NuGet はファイルの参照を解決する優先順位を理解します。
  • ソリューション パッケージがサポートされなくなるため。これらのパッケージは、特定のプロジェクトの機能を変更することはなく、通常、プロジェクト間で再利用される共有リソースを提供するために使用されます。新しい共有パッケージ フォルダーにより、こうした共有リソースが別のプロジェクトで既に用意している可能性があります。

新しいターゲット フレームワーク

新しいバージョンの NuGet のもう 1 つの側面は、新しい開発フレームワークのサポートと、複数の OS やアーキテクチャ間でのネイティブ パッケージ サポートの強化です。NuGet はサポート範囲を .NET Framework のマネージ モデル以外の多くのエコシステムに広げ、以前は対象にしていなかった環境にライブラリを提供します。

ターゲット フレームワーク モニカー (TFM) とは、バイナリがサポートするフレームワークや、各フレームワークが必要とする依存関係を宣言するためのパッケージを作成する際に使用する省略表現です。パッケージの lib フォルダーや ref フォルダーのフォルダー名にこうした省略表現が使われるのを確認できます。パッケージの nuspec 依存関係要素でも、TFM 値の 1 つを使ってターゲット フレームワーク属性を宣言し、使用側のプロジェクトに適切なライブラリを提供するように NuGet クライアントに指示しています。

図 2 には、現在も利用可能な TFM と新たに導入された TFM を一覧しています。

図 2 NuGet 3.x によってサポートされるターゲット フレームワーク

説明 基本コード 利用可能なバージョン
マネージ フレームワーク アプリケーション (Windows フォーム、コンソール アプリケーション、Windows Presentation Foundation、ASP.NET) net net11、net20、net35、net35-client、net35-full、net4、net40、net40-client、net40-full、net403、net45、net451、net452、net46
ASP.NET 5 dnxcore dnxcore50
Windows ストア netcore win8 = netcore45、win81 = netcore451、uap10.0
Windows Phone (appx モデル) wpa wpa81
Windows Phone (Silverlight) wp wp7 = sl3-wp、wp71 = sl4-wp71、sl4-wp, wp8 = wp8-、wp81
Silverlight sl sl2、sl3 = sl30、sl4 = sl40、sl5 = sl50
Xamarin   mono、MonoMac、Xamarin.Mac、MonoAndroid10、MonoTouch10、Xamarin.iOS10
Compact Framework net-cf net20-cf、net35-cf = cf35、net40-cf
Micro Framework netmf netmf41、netmf42、netmf43

上記の一覧で等号 (=) を付けた項目は、NuGet がサポートする同義語です。多種多様なフレームワークに対して多くのサポートがありますが、これが混乱の原因になる可能性があります。マネージ フレームワーク パッケージ内で Micro Framework のサポートを提供する必要はあるでしょうか。Silverlight のサポートはどの程度必要なのでしょう。顧客のニーズを完全に満たすには、これらの疑問を解決する必要があります。

この表には PCL のサポートが明らかに存在しません。NuGet は上記のフレームワークの組み合わせをサポートしていますが、最新のPCL にはより上位互換性の高いモニカーが必要です。その結果、パッケージの構築やサポートするフレームワークを定義する際に、より高い柔軟性が得られます。NuGet 3.1 では、最新の PCL に対して dotnet ターゲット モニカーが導入されます。

dotnet ターゲット モニカー

以前のバージョンの NuGet では、TFM の省略表現をプラス記号でつないだ集合体として PCL を表現し、フレームワークを指定していました。たとえば、「portable-net45+win8+wpa81+wp8」のようにフォルダー名を指定します。これは混乱を招き、互換性の問題につながる可能性がありました。PCL やクロスプラットフォーム開発エクスペリエンスを容易にするために、NuGet は dotnet モニカーを導入しました。

このモニカーは、特定のバージョンのフレームワーク機能に直接結び付いていません。「これは、使用しているフレームワークとランタイムの機能がサポートされている場合に使用すべき参照です」と NuGet に指示する間接参照です。これにより、NuGet クライアントはその参照を調べて、サポートする機能とフレームワークを判断します。このプロセスは、NuGet クライアントが doenet 参照によりサポートされている正確な機能を解決するまで続きます。その後、機能とプロジェクトの要件が一致した場合のみ、そのサポートを適用します。Xamarin Android や Xamarin iOS など、.NET Framework 4.5 以降から派生されたバージョンのフレームワークでは、dotnet モニカーを参照できます。

ただし、PCL を単純にビルドして、宣言した dotnet 依存関係をそのビルドにバンドルすれば終わりというわけではありません。以前のバージョンの Visual Studio と NuGet クライアントを使用し、従来のポータブル クラス ライブラリでビルドするプロジェクトをサポートできるようにする場合は、依然として、完全な PCL ターゲット フレームワーク モニカーへの参照を作成して配置する必要があります。

dotnet モニカーと完全な互換性のあるプロジェクトの種類 (NET Framework 4.6、UWP、または ASP.NET 5) にパッケージをインストールしているときは、dotnet モニカーは最後にシークされます。これは、特定のフレームワークまたはあまりプロジェクト固有ではないフレームワークに一致する参照のシークを試みた後に行われます。このシークの階層は図 3 のようになります。

UWP の参照を検査するフレームワークの階層
図 3 UWP の参照を検査するフレームワークの階層

プロジェクトが、上記のフレームワークのいずれかのみをターゲットにする project.json を使用している最新の PCL の場合、dotnet モニカーが最初に分析されます。その後は、標準の PCL 解決手順が実行されます (図 4 参照)。

最新ポータブル クラス ライブラリ プロジェクトでの参照を検査するフレームワークの階層
図 4 最新ポータブル クラス ライブラリ プロジェクトでの参照を検査するフレームワークの階層

NuGet コマンド ライン

NuGet のコマンドライン実行可能ファイル (nuget.exe) では、packages.config ファイルまたは project.json ファイルのいずれかを使用するプロジェクトに対して、パッケージのインストール、更新、復元のサポートが行えるようになります。pack コマンドは、引き続き、ディスク上の nuspec ファイルや packages.config を操作します。project.json ファイルを基に nuspec ファイルを生成するようには更新はされていません。これを回避するには、project.json のパッケージ参照により構成する新しいパッケージのコンテンツ用に、独自の nuspec ファイルを作成する必要があります。今後のリリースには、この問題に対処する更新が含まれる予定です。

現バージョンのコマンドライン 実行可能ファイルは、NuGet.org v3 エンドポイントもサポートします。この新しいバージョンの nuget.org フィードは、操作をより高速にし、サービスの信頼性を高めています。フィードには、迅速なパッケージ配信を支援する、組み込みの冗長性とコンテンツ配信ネットワークがあります。更新された NuGet.exe のコピーは、bit.ly/1UV0kcU からダウンロードできます。

NuGet の拡張機能をアップグレードした後、Windows 10 SDK/Windows 10 ツールをインストールすると、インストーラーはその拡張機能をバージョン 3.1 にダウングレードします。ユーザーは、最低でも 3.1.1 に拡張機能を再度更新する必要があります。[拡張機能と更新プログラム] ダイアログに表示されるバージョンは 3.1.60724.766 です。Windows PowerShell コンソールは 3.1.1.0 です。

まとめ

Windows 10 UWP アプリケーション開発や PCL プロジェクトをサポートする機能が利用できるようになりました。こうした変更は、パッケージ マネージャーや .NET Framework を幅広く使うための第 1 歩です。マイクロソフトは .NET の開発エクスペリエンスの強化を続け、あらゆるプラットフォームでさまざまな種類のプロジェクトをビルドするすべての .NET 開発者をサポートするためのパッケージ マネージャーの提供を目指します。


Jeffrey T. Fritzは、マイクロソフトの NuGet チームに所属するシニア プログラム マネージャーです。彼は時間をかけてビーチの散歩を楽しんだり、クラウドでスケーリングを行うすばらしい Web アプリケーションを開発したりしています。連絡先は jfritz@microsoft.com (英語のみ) です。

この記事のレビューに協力してくれたマイクロソフトの NuGet チームのメンバーに心から感謝します。