Ключевой инструмент для любой современной платформы разработки — это механизм, с помощью которого разработчики могут создавать, передавать друг другу и использовать полезный код. Часто такой код распределен по "пакетам", включающим скомпилированный код (в виде библиотек DLL) и другое содержимое, необходимое использующим эти пакеты проектам.
Для .NET (в том числе .NET Core) механизмом совместного использования кода, поддерживаемым Майкрософт, является NuGet, который определяет, как создаются, размещаются и используются пакеты для .NET, а также предоставляет средства для каждой из этих ролей.
Проще говоря, пакет NuGet представляет собой отдельный ZIP-файл с расширением .nupkg, который содержит скомпилированный код (DLL), другие файлы, связанные с этим кодом, и описательный манифест, включающий такие сведения, как номер версии пакета. Разработчики, у которых есть код, к которому нужно предоставить общий доступ, создают пакеты и публикуют их на закрытых или открытых узлах. Потребители получают эти пакеты из соответствующих узлов, добавляют их в свои проекты, а затем вызывают функции пакета в коде своего проекта. При этом NuGet сам обрабатывает все промежуточные данные.
Так как NuGet поддерживает закрытые узлы наряду с открытым узлом nuget.org, с помощью пакетов NuGet вы можете делиться кодом, используемым в рамках организации или рабочей группы. Пакеты NuGet также являются удобным способом факторизовать свой код для использования только в собственных проектах. Иными словами, пакет NuGet является совместно используемой единицей кода, однако не требует и не подразумевает какого-либо определенного способа предоставления общего доступа.
Поток пакетов между создателями, узлами и потребителями
В качестве общедоступного узла NuGet сам поддерживает центральный репозиторий более 100 000 уникальных пакетов в nuget.org. Эти пакеты используются миллионами разработчиков .NET/.NET Core каждый день. NuGet также позволяет размещать пакеты в частном порядке в облаке (например, в Azure DevOps), в частной сети или даже в вашей локальной файловой системе. Таким образом эти пакеты доступны только тем разработчикам, у которых есть доступ к узлу, что позволяет сделать их доступными для отдельных групп потребителей. Эти возможности описаны в разделе Размещение своих веб-каналов NuGet. С помощью параметров конфигурации можно также контролировать, какие узлы могут быть доступны любому компьютеру, тем самым гарантируя, что пакеты получают из определенных источников, а не из общего репозитория, такого как nuget.org.
Независимо от своей природы, узел выступает в качестве точки подключения между создателями и потребителями пакета. Создатели разрабатывают полезные пакеты NuGet и публикуют их на узле. Потребители ищут полезные и совместимые пакеты на доступных узлах, скачивая эти пакеты и включая их в свои проекты. После установки в проекте API пакеты становятся доступны остальной части кода проекта.
Совместимость пакета с разными целевыми платформами
"Совместимый" пакет означает, что он содержит сборки, созданные по меньшей мере для одной целевой платформы .NET, совместимой с целевой платформой используемого проекта. Разработчики могут создавать пакеты, которые относятся к одной платформе, как и элементы управления универсальной платформы Windows (UWP), или они могут поддерживать более широкий набор целевых объектов. Для максимальной совместимости пакета разработчики используют версию .NET Standard, которую поддерживают все проекты .NET и .NET Core. Это наиболее эффективное средство как для создателей, так и для потребителей, так как единый пакет (обычно содержащий единую сборку) подходит для всех потребляющих проектов.
Разработчики пакетов, которым требуется API вне .NET Standard, с другой стороны, создают отдельные сборки для различных требуемых версий .NET Framework, которые они будут поддерживать, и включают все эти сборки в один пакет (который называется пакетом многоплатформенного нацеливания). Когда потребитель устанавливает такой пакет, NuGet извлекает только сборки, нужные в проекте. Это сводит к минимуму занимаемое пакетом место в конечном приложении или сборках, создаваемых данным проектом. Пакет настройки для различных версий, конечно, сложнее в обслуживании.
Кроме поддержки размещения, NuGet также предоставляет широкий набор средств, используемых как создателями, так и потребителями. Сведения о получении конкретных средств см. в разделе Установка клиентских средств NuGet.
Средство CLI для библиотек .NET Core и .NET Standard, а также для проектов в стиле пакета SDK, нацеленных на .NET Framework (см. раздел Атрибут SDK). Предоставляет определенные возможности CLI NuGet непосредственно внутри цепочки инструментов .NET Core. Как и CLI nuget.exe, CLI dotnet не взаимодействует с проектами Visual Studio.
Средство CLI для библиотек .NET Framework и проектов не в стиле пакета SDK, нацеленных на библиотеки .NET Standard. Предоставляет все функциональные возможности NuGet, при этом часть команд относится к создателям пакета, часть — только к потребителям, а остальные — ко всем. Например, создатели пакета используют команду nuget pack для создания пакета из различных сборок и связанных файлов, потребители пакета используют nuget install для включения пакетов в папку проекта, при этом все используют nuget config для задания переменных конфигурации NuGet. Как независящее от платформы средство, интерфейс командной строки NuGet не взаимодействует с проектами Visual Studio.
Предоставляет возможность создавать и восстанавливать используемые в проекте пакеты напрямую с помощью цепочки инструментов MSBuild.
Как видите, средства NuGet, с которыми вы работаете, в значительной степени зависят от того, создаете, потребляете или публикуете вы пакеты, а также от используемой платформы. Создатели пакета обычно также являются потребителями, так как берут за основу функции, имеющиеся в других пакетах NuGet. Конечно же, те пакеты, в свою очередь, могут зависеть еще от каких-либо.
Возможность легко брать за основу работу других — это одна из наиболее мощных функций системы управления пакетами. Соответственно, значительная часть работы NuGet заключается в управлении этим деревом или "схемой" зависимостей от имени проекта. Проще говоря, вам нужно заботиться только о тех пакетах, которые вы используете непосредственно в проекте. Если эти пакеты используют другие пакеты (которые, в свою очередь, также используют пакеты), все эти зависимости нижнего уровня обрабатывает NuGet.
На следующем рисунке показан проект, зависящий от пяти пакетов, которые, в свою очередь, зависят от нескольких других.
Обратите внимание, что некоторые пакеты встречаются на графе зависимостей несколько раз. Например, существует три разных потребителя пакета B, и каждый из них может также указывать другую версию этого пакета (не показано). Это обычное дело, особенно для широко используемых пакетов. NuGet выполняет всю работу, чтобы определить, какая именно версия пакета B отвечает потребностям всех потребителей. Затем NuGet делает то же самое для всех других пакетов, независимо от того, насколько глубока схема зависимостей.
Дополнительные сведения о том, как NuGet выполняет эту задачу, см. в разделе Разрешение зависимостей.
Отслеживание ссылок и восстановление пакетов
Так как проекты можно легко перемещать между компьютерами разработчиков, репозиториями управления исходным кодом, серверами сборки и т. д., крайне непрактично хранить двоичные сборки из пакетов NuGet напрямую привязанными к проекту. В этом случае каждая копия проекта будет излишне раздутой (и, следовательно, расходовать пространство в репозиториях системы управления исходным кодом). Кроме того, обновить двоичные файлы пакета до новой версии будет очень сложно, так как обновление будет применяться ко всем копиям проекта.
Вместо этого NuGet поддерживает простой список ссылок на пакеты, от которых зависит проект, включая зависимости верхнего и нижнего уровня. То есть при установке пакета с некоторого узла в проект NuGet записывает идентификатор пакета и номер версии в этот список ссылок. (Удаление пакета, конечно, удаляет его из списка.) Затем NuGet предоставляет средства для восстановления всех ссылочных пакетов по запросу, как описано в разделе "Восстановление пакетов".
С помощью только списка ссылок NuGet может переустановить (то есть восстановить) все эти пакеты из общедоступных и /или частных узлов в любое время. При фиксации проекта в системе управления исходным кодом или предоставления его для общего доступа каким-либо иным образом нужно включить только список ссылок и исключить какие-либо двоичные файлы пакета (см. раздел Пропуск пакетов NuGet в системах управления исходным кодом.)
Компьютер, принимающий проект, например сервер сборки, получающий копию проекта в рамках работы системы автоматического развертывания, просто запрашивает у NuGet восстановление зависимости всякий раз, когда они понадобятся. Системы сборки, такие как Azure DevOps, предоставляют шаги "Восстановление NuGet" именно для этой цели. Аналогично, когда разработчики получают копию проекта (например, при клонировании репозитория), они могут вызвать такие команды, как nuget restore (CLI NuGet), dotnet restore (CLI dotnet) или Install-Package (консоль диспетчера пакетов), чтобы получить все необходимые пакеты. Visual Studio, со своей стороны, автоматически восстанавливает пакеты при создании проекта (при условии, что включено автоматическое восстановление, как описано в статье Восстановление пакетов).
Очевидно, что основная роль NuGet, связанная с разработчиками, заключается в обслуживании этого списка ссылок от имени проекта и предоставлении средств для эффективного восстановления (и обновления) таких указанных в ссылках пакетов. Этот список хранится в одном из двух указанных ниже форматов управления пакетами:
PackageReference (также известном как "Ссылки на пакет в файлах проекта"): (NuGet 4.0 и более поздних версий) ведет список зависимостей верхнего уровня проекта непосредственно в файле проекта, поэтому отдельный файл не требуется. Связанный файл obj/project.assets.json создается динамически. Этот файл позволяет управлять общей схемой зависимостей пакетов, которые проект использует со всеми зависимостями нижнего уровня. В проектах .NET Core всегда используется формат PackageReference.
packages.config: (NuGet 1.0+) XML-файл, содержащий плоский список всех зависимостей в проекте, включая зависимости других установленных пакетов. Установленные или восстановленные пакеты хранятся в папке packages.
Применение конкретного формата управления пакетами зависит от типа проекта и доступной версии Visual Studio и NuGet. Чтобы проверить, какой формат используется, просто найдите packages.config в корневом каталоге проекта после установки первого пакета. Если этот файл отсутствует, найдите в файле проекта элемент <PackageReference>.
При наличии возможности выбора рекомендуем использовать PackageReference. Файл packages.config используется в устаревших версиях и больше не применяется в активной разработке.
Совет
Различные команды интерфейса командной строки nuget.exe, например nuget install, не добавляют автоматически пакет в список ссылок. Этот список обновляется при установке пакета с помощью диспетчера пакетов Visual Studio (пользовательского интерфейса или консоли) и интерфейса командной строки dotnet.exe.
Что еще делает NuGet?
Мы уже выучили следующие характеристики NuGet:
NuGet предоставляет центральный репозиторий nuget.org с поддержкой частного размещения.
NuGet предоставляет разработчикам средства для создания, публикации и использования пакетов.
Самое главное, NuGet ведет список ссылок для пакетов, используемых в проекте, а также позволяет восстанавливать и обновлять пакеты из этого списка.
Чтобы обеспечить эффективную работу этих процессов, NuGet осуществляет некоторые оптимизации в фоновом режиме. В частности, NuGet управляет кэшем пакета и папкой глобальных пакетов, что позволяет упростить установку и повторною установку. Кэш позволяет избежать загрузки пакета, который уже установлен на компьютере. Папка глобальных пакетов позволяет в нескольких проектах совместно использовать один установленный пакет, тем самым уменьшая общий размер пакетов NuGet на компьютере. Это очень удобно, когда вы часто восстанавливаете большее количество пакетов, например, как на сервере сборки. Дополнительные сведения об этих механизмах см. в статье Управление папкой установки глобальных пакетов, кэшем и временными папками.
В рамках отдельного проекта NuGet управляет общей схемой зависимостей, что включает в себя разрешение нескольких ссылок на различные версии одного пакета. Довольно часто проект зависит от одного или нескольких пакетов, имеющих такие же зависимости. Некоторые из наиболее полезных пакетов служебных программ на сайте nuget.org используются многими другими пакетами. В общей схеме зависимостей вы легко можете иметь десять различных ссылок на разные версии одного пакета. Чтобы избежать переноса нескольких версий этого пакета в само приложение, NuGet определяет, какую отдельную версию могут использовать все потребители. (Дополнительные сведения см. в разделе Принципы разрешения зависимостей пакетов в NuGet.)
Помимо этого NuGet поддерживает все спецификации, связанные с структурой пакетов (включая локализацию и отладочные символы), а также как они ссылаются (включая диапазоны версий и версии предварительной версии). NuGet также предоставляет различные API для программной работы со своими службами и предоставляет поддержку разработчикам, которые пишут расширения Visual Studio и шаблоны проектов.
Если изучить содержание этой документации, можно найти все указанные возможности и заметки о выпуске, отсылающие к самому начальному этапу развития NuGet.
Наконец, мы очень приветствуем комментарии и вклады в эту документацию— просто выберите команды "Отзывы и изменения " на верхней части любой страницы или посетите репозиторий документов и список проблем с документами на сайте GitHub.
Создайте проект .NET и узнайте, как добавлять пакеты и управлять зависимостями пакетов в проекте. Используйте .NET Core CLI и реестр NuGet для добавления библиотек и средств в приложения C# с помощью Visual Studio Code.