Special Windows 10 issue 2015
Volume 30 Number 11
Инструментарий Visual Studio - Новые средства NuGet для разработки под Windows 10
Джеффри Т. Фриц | Windows 2015
Продукты и технологии:
Windows 10, Visual Studio 2015, ASP.NET 5, NuGet 3.1
В статье рассматриваются:
- добавление поддержки NuGet в проекты для Windows 10;
- определение пакетов и зависимостей;
- обеспечение совместимости между пакетами.
Группа NuGet выпустила несколько новых утилит. Мы работали в сотрудничестве с несколькими другими группами в Microsoft, чтобы предоставить вам новую версию клиента NuGet, который поддерживает Universal Windows Platform (UWP) и новые Portable Class Libraries (PCL). Новые утилиты NuGet доступны через Tools | Extensions and Updates | Update in Visual Studio 2015, а также на сайте дистрибуции NuGet (bit.ly/1MgNt2J). NuGet также выпустила новую версию утилиты командной строки NuGet, которую можно скачать с dist.nuget.org. В этой статье будет дан обзор новых возможностей и процесса, которому должны следовать Windows-разработчики, чтобы добавить поддержку NuGet в свои проекты для Windows 10.
Project.Json
Начиная с ASP.NET 5, группа NuGet ввела поддержку файла project.json, который описывает зависимости проекта с четким определением пакетов, от которых вы зависите напрямую. В ASP.NET 5 это единственный файл, определяющий конфигурацию проекта. Однако с появлением NuGet 3.1 вы используете этот файл в проектах для UWP и современных PCL (ориентированных на DNX, UWP и Microsoft .NET Framework 4.6) для определения ссылок вашего пакета. Хорошая новость в том, что диалог Manage Packages в Visual Studio будет соответственно поддерживать ваш файл packages.config или project.json за вас, исходя из типа разрабатываемого проекта.
Этот отход от модели packages.config также позволяет вам «перезапускать» ссылки в своих проектах и использовать новые возможности транзитивных зависимостей (transitive dependency capabilities) в NuGet. Разработчики и авторы пакетов сообщали группе NuGet, что, когда они добавляли пакеты в проекты, их файл packages.config загрязнялся зависимостями от зависимых пакетов.
Например, NHibernate — это пакет, зависимый от пакета Iesi.Collections. В packages.config есть две ссылки: на NHibernate и Iesi.Collections. Когда нужно обновить NHibernate, возникает вопрос: «Должен ли я обновить и Iesi.Collections?». Также существует противоположная проблема. Если появилось обновление для Iesi.Collections, надо ли обновлять NHibernate для поддержки новых средств в Iesi.Collections? В итоге разработчики могли попасть в этот кошмарный цикл управления зависимостями пакета в проекте из-за его ссылок на другие пакеты.
Функция транзитивных зависимостей в NuGet абстрагирует решение об обновлении ссылок пакета с улучшенной поддержкой семантического контроля версий в файле определений пакетов (документах nuspec). Разработчики указывают диапазон версий зависимостей, поддерживаемых их пакетами. Когда NuGet устанавливает клиенты, эти зависимости добавляют жесткую ссылку на конкретную версию в файле packages.config, и такие ссылки выглядят, как и любые другие ссылки на пакеты, добавленные в проект. Отличный пример этой проблемы показан на рис. 1.
Рис. 1. Содержимое файла packages.config в ASP.NET MVC
<?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. Другие элементы, на которые ссылаются эти четыре пакета, являются просто шумом, и теперь у меня имеются жесткие ссылки на конкретные версии. Благодаря функции транзитивных зависимостей версии других пакетов исключаются. Мне остается управлять лишь теми четырьмя библиотеками, реально используемыми в моем проекте.
Клиент NuGet будет разрешать и управлять этими другими пакетами скрытно от вас и поддерживать соответствующие ссылки в рамках ограничений зависимых версий, объявленных пакетами, которые непосредственно используются в проекте. Это должно радикально упростить работу со ссылками в проекте.
Общий локальный кеш пакетов
Зачастую у разработчиков свои наборы пакетов и инструментов, которыми они предпочитают пользоваться. Зачем многократно скачивать и устанавливать их на одной рабочей станции, когда очевидно, что вы уже используете их в одном проекте и хотите использовать в другом? В случае проектов, управляемых project.json, NuGet скачивает и сохраняет копии пакетов в глобальной папке пакетов, расположенной в вашей папке %userprofile%\.nuget\packages. Это должно сократить размер занимаемого дискового пространства на рабочей станции. Кроме того, это исключает лишние вызовы для выборки тех пакетов с NuGet.org, которые у вас уже имеются.
Поддержка project.json и общего локального кеша пакетов доступна для ASP.NET 5 с NuGet 3.0, а для других типов проектов нужен NuGet версии не ниже 3.1.
Устаревшие средства
Начиная с NuGet 3.1 при условии использования project.json, вы прекращаете поддерживать выполнение скриптов install.ps1/uninstall.ps1 и создание элементов в папке пакетов /content. Установка пакетов с этими элементами не позволит ни выполнить файл install.ps1, ни скопировать контент в ваш проект. Однако в проектах, которые все еще используют файлы packages.config, текущее поведение пока поддерживается. На то есть несколько причин:
- при восстановлении транзитивных пакетов надежный выбор того, что нужно удалить, а что — установить, невозможен;
- при копировании контента в проект пользователя, если пакеты обновляются, запускается неявный процесс удаления, который нельзя безопасно выполнять;
- NuGet должен полностью поддерживать разработку вне Visual Studio. С переходом на полную поддержку кросс-платформенной .NET-разработки следует учитывать, что в других средах Windows Powershell недоступен. Кроме того, все больше разработчиков работают над .NET-кодом вне Visual Studio, и их нужно поддерживать;
- другие диспетчеры пакетов обеспечивают отличное управление и доставку контента. NuGet хорошо работает как диспетчер пакетов для .NET Framework, поэтому для данной инфраструктуры рекомендуется по-прежнему использовать именно его;
- больше нет поддержки «любой» инфраструктуры. Вы больше не можете помещать файлы напрямую в корень папок build и lib и включать их в проект. Важно объявить, какие инфраструктуры поддерживают ваши файлы, чтобы NuGet знал приоритет в разрешении соответствующих ссылок;
- пакеты решения больше не поддерживаются. Эти пакеты не модифицируют какие-либо специфические возможности проекта и обычно служили для доставки общих ресурсов, которые повторно использовались между проектами. С появлением новой папки общих пакетов эти ресурсы уже могут находиться на диске, если они есть в каком-то другом проекте.
Новые целевые инфраструктуры
Другой аспект новой версии NuGet — поддержка новых инфраструктур разработки и улучшенная поддержка «родных» для разных операционных систем и архитектур пакетов. NuGet выходит за рамки одной лишь модели .NET Framework для поддержки большего количества экосистем и позволяет задействовать библиотеки в ранее недоступных средах.
Моникеры целевых инфраструктур (target framework monikers, TFM) — это сокращение (shorthand), применяемое при создании пакетов для объявления поддержки двоичных файлов конкретных инфраструктур и их зависимостей. Вы найдете в папках lib и ref пакета имена папок, где используется эта нотация. Кроме того, есть элементы в элементе зависимостей nuspec пакета, которые объявляют атрибут целевой инфраструктуры с помощью одного из TFM-значений, чтобы указать клиенту NuGet доставить соответствующую библиотеку в проект, где она должна использоваться.
В табл. 1 перечислены по-прежнему доступные TFM и новые TFM.
Табл. 1. Целевые инфраструктуры, поддерживаемые NuGet 3.x
Описание | Базовый код | Доступные версии |
Приложения управляемых инфраструктур (Windows Forms, Console Applications, 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 Store | 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. Это огромный объем поддержки для множества разных инфраструктур — в ней можно запутаться. Нужно ли вам поддерживать микро-инфраструктуру в своем пакете управляемой инфраструктуры? Насколько глубокая поддержка Silverlight требуется именно вам? Вы должны ответить на эти вопросы, чтобы лучше удовлетворить потребности своих пользователей.
Вы заметите, что в табл. 1 нет явного названия для поддержки PCL. Хотя NuGet поддерживает комбинации инфраструктур, мы хотим, чтобы у вас был более совместимый «снизу вверх» (forward-compatible) моникер для современных PCL. Это даст вам большую гибкость в конструировании пакетов и определении поддерживаемых вами инфраструктур. В NuGet 3.1 введен целевой моникер dotnet (dotnet target moniker) для современных PCL.
Целевой моникер dotnet
В предыдущих версиях NuGet вы могли указывать инфраструктуры с какой-либо PCL, которая работала как набор TFM-аббревиатур, соединенных знаками «плюс». В итоге вы могли получить такие имена папок, как «portable-net45+win8+wpa81+wp8». Это могло создать путаницу и привести к проблемам несовместимости для ваших пользователей. Чтобы упростить кросс-платформенную разработку и создание PCL, NuGet ввела моникер dotnet.
Этот моникер не привязан напрямую к возможностям какой-либо конкретной версии или инфраструктуры. Это непрямую ссылка, которая сообщает NuGet: «Это ссылка, которую следует использовать, если она поддерживает имеющиеся инфраструктуру и возможности исполняющей среды». Тогда клиент NuGet анализирует эту ссылку, чтобы определить, какой функционал и инфраструктуры она поддерживает. Этот процесс продолжается, пока клиент NuGet не разрешит точные возможности, поддерживаемые ссылкой dotnet. Затем он применит ее, только если она соответствует средствам и требованиям вашего проекта. Вы можете ссылаться на моникер dotnet в .NET Framework версий от 4.5 и выше, а также в соответствующих версиях производных инфраструктур, включая Xamarin Android и Xamarin iOS.
Это не означает, что вы можете просто создать PCL, упаковать с объявленными зависимостями dotnet, и на этом все. Если вы хотите иметь возможность поддерживать проекты, использующие более старые версии Visual Studio и клиентов NuGet, созданных с помощью традиционных библиотек портируемых классов, то все равно должны создать и поместить ссылку на полный моникер целевой инфраструктуры PCL.
При установке пакета в проект того типа, который полностью совместим с моникером dotnet (.NET Framework 4.6, UWP или ASP.NET 5), моникер dotnet будет последним в процессе поиска. Это произойдет после попытки найти ссылку, которая совпадает с конкретной или менее специфичной инфраструктурой вашего проекта. Такая иерархия выглядит, как показано на рис. 2.
Рис. 2. Иерархия инфраструктур, проверяемых на ссылки для проекта Universal Windows Platform
Если ваш проект — это современная PCL, использующая project.json, который ориентирован на какую-либо из этих инфраструктур и ни на какую другую, моникер dotnet будет анализироваться первым. Процесс будет следовать стандартной стратегии разрешения PCL, как на рис. 3.
Рис. 3. Иерархия инфраструктур, проверяемых на ссылки в проекте Modern Portable Class Library
dotnet | dotnet |
PCL containing your targets | PCL, содержащая ваши целевые инфраструктуры |
portable-* | portable-* |
Командная строка NuGet
Теперь доступен подобный команде исполняемый файл для NuGet, nuget.exe, и он поддерживает установку, обновление и восстановление пакетов в проекте либо через файл packages.config, либо через файл project.json. Команда pack по-прежнему работает с файлами nuspec на диске и файлами packages.config. Она не обновлялась для генерации файла nuspec на основе project.json. Чтобы обойти эту проблему, вам придется создавать собственный файл nuspec для любого нового контента пакета, конструируемого с использованием ссылки на пакеты, которые используют project.json. В следующий выпуск будет включено обновление, устраняющее эту проблему.
Данная версия исполняемого файла командной строки также поддерживает конечные точки NuGet.org v3. Эта новая версия канала nuget.org ускоряет взаимодействие и является более надежным сервисом. В быстрой доставке пакетов помогает встроенная поддержка избыточности и включенная сеть доставки контента (content-delivery network, CDN). Скачайте копию обновленного NuGet.exe по ссылке bit.ly/1UV0kcU.
Если вы установили Windows 10 SDK или Windows 10 Tools после обновления расширения NuGet, установщик откатит расширение обратно к версии 3.1. Из-за этого вам потребуется снова обновить его минимум до версии 3.1.1. Версия, показываемая в диалоге Extensions and Updates, — 3.1.60724.766. Консоль Windows PowerShell имеет версию 3.1.1.0.
Заключение
Теперь вам доступны средства, поддерживающие разработку приложений и проектов PCL для Windows 10 UWP. Эти изменения являются первым шагом в более широком применении диспетчера пакетов и .NET Framework. Microsoft продолжает улучшать .NET-разработку и в ближайшее время будет сосредоточена на том, чтобы предоставить диспетчер пакетов, пригодный для всех .NET-разработчиков проектов любых типов на любой платформе.
Джеффри Т. Фриц (Jeffrey T. Fritz) — старший менеджер программ в Microsoft, работает в группе NuGet. Любит долгие прогулки по пляжу и «убойные» веб-приложения, масштабируемые в облаке. С ним можно связаться по адресу jefritz@microsoft.com.
Выражаю благодарность за рецензирование статьи членам группы NuGet в Microsoft.