Пакеты NuGet: подключение и управление зависимостями

Тема дорожной карты · .NET / C# Developer

Пакет NuGet — это zip-архив с расширением .nupkg, внутри которого лежат скомпилированные сборки, манифест .nuspec и иногда файлы сборки. Практически любой проект на C# состоит из вашего кода и десятков таких пакетов: логирование, сериализация, драйверы баз данных, тестовые фреймворки. Умение грамотно подключать, фиксировать и обновлять зависимости отличает проект, который воспроизводимо собирается через год, от проекта, который «внезапно» перестал компилироваться после обновления одной библиотеки.

Как это работает

Зависимость объявляется в файле проекта элементом <PackageReference Include="Serilog" Version="4.1.0" />. Команда dotnet add package Serilog делает то же самое из терминала, а при первом dotnet restore клиент скачивает пакет и все его транзитивные зависимости из источников, перечисленных в nuget.config. По умолчанию источник один — nuget.org, но в корпоративной среде туда добавляют приватный фид: Azure Artifacts, GitHub Packages, Nexus или локальную папку.

Версия в PackageReference — на самом деле диапазон. Запись 4.1.0 означает «минимум 4.1.0», [4.1.0] — строго эту версию, [4.0,5.0) — любую четвёртую мажорную. Восстановление выбирает наименьшую версию, удовлетворяющую всем ограничениям графа, поэтому две библиотеки, которые просят разные версии одной зависимости, разрешаются в одну общую. Результат разрешения попадает в obj/project.assets.json; чтобы зафиксировать его окончательно, включают RestorePackagesWithLockFile — тогда рядом появляется packages.lock.json, и в CI восстановление с флагом --locked-mode упадёт, если граф изменился.

В больших решениях версии выносят в один файл Directory.Packages.props с элементами <PackageVersion>; это называется центральным управлением пакетами. Проекты тогда ссылаются на пакет без версии, и обновление библиотеки во всём решении сводится к правке одной строки.

Когда применять

Прямой PackageReference с минимальной версией достаточен для небольшого сервиса или библиотеки. Lock-файл и режим --locked-mode обязательны для продуктов, где сборка должна быть воспроизводимой: банковские системы, дистрибутивы, всё, что проходит аудит. Центральное управление пакетами стоит включать, как только в решении больше пяти проектов, иначе одна и та же библиотека расползается по разным версиям. Приватный фид нужен, когда команда публикует внутренние пакеты или хочет кэшировать внешние, чтобы сборка не зависела от доступности nuget.org.

Типичные ошибки

Самая частая проблема — конфликт версий транзитивных зависимостей: две библиотеки тянут разные мажорные версии, и в рантайме падает FileLoadException. Лечится явной прямой ссылкой на нужную версию в самом проекте. Вторая — забытый nuget.config с приватным фидом: локально всё собирается, а в CI восстановление не находит пакет. Файл нужно класть в репозиторий и хранить учётные данные в переменных окружения, а не в тексте.

Уязвимые пакеты обнаруживает dotnet list package --vulnerable; начиная с .NET 8 восстановление само выводит предупреждения NU1901–NU1904. Их стоит превратить в ошибки сборки через <WarningsAsErrors>. Наконец, не удаляйте packages.lock.json при каждом расхождении: сначала выясните, какая зависимость изменилась и почему.

Связанные понятия

Полезные ресурсы

🔤 Английские термины в этой теме

Слова из этой темы, которые русскоязычные часто произносят неверно. Кнопка 🔊 произносит голосом браузера.

Весь словарь терминов →