Централизованное управление пакетами (CPM)
Управление зависимостями — это основная функция NuGet. Управление зависимостями для одного проекта может быть простым. Управление зависимостями для решений с несколькими проектами может оказаться трудным, так как они начинают масштабироваться по размеру и сложности. В ситуациях, когда вы управляете общими зависимостями для многих различных проектов, вы можете использовать центральные функции управления пакетами NuGet (CPM), чтобы сделать все это с легкостью в одном расположении.
Исторически сложилось, что зависимости пакетов NuGet управлялись в одном из двух мест.
-
packages.config
— XML-файл, используемый в старых типах проектов для поддержания списка пакетов, на которые ссылается проект. -
<PackageReference />
— XML-элемент, используемый в проектах MSBuild, определяет зависимости пакетов NuGet.
Начиная с NuGet 6.2, вы можете централизованно управлять зависимостями в проектах с добавлением файла Directory.Packages.props
и свойства MSBuild.
Эта функция доступна во всех интегрированных инструментах NuGet, начиная со следующих версий.
Старые средства игнорируют конфигурации и функции централизованного управления пакетами. Чтобы использовать эту функцию в полной степени, убедитесь, что все среды сборки используют последние версии совместимых инструментов.
Централизованное управление пакетами применяется ко всем проектам MSBuild на основе <PackageReference>
(включая устаревшиеCSPROJ) при условии использования совместимого средства.
Включение централизованного управления пакетами
Чтобы приступить к работе с центральным управлением пакетами, необходимо создать файл Directory.Packages.props
в корне репозитория и задать для свойства MSBuild значение ManagePackageVersionsCentrally
true
.
Его можно создать вручную или использовать dotnet CLI:
dotnet new packagesprops
Затем внутри вы определяете каждую из соответствующих версий пакетов, необходимых для ваших проектов, с помощью элементов <PackageVersion />
, которые указывают идентификатор пакета и версию.
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>
Для каждого проекта необходимо определить <PackageReference />
, но опустить атрибут Version
, так как версия будет получена из соответствующего элемента <PackageVersion />
.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>
</Project>
Теперь вы используете централизованное управление пакетами и управляете версиями в централизованном месте!
Правила централизованного управления пакетами
Файл Directory.Packages.props
имеет ряд правил относительно расположения в каталоге репозитория и его контексте. Для простоты вычисляется только один файл Directory.Packages.props
для данного проекта.
Это означает, что если в вашем репозитории несколько файлов Directory.Packages.props
, то будет оцениваться файл, который находится ближе всего к каталогу вашего проекта. Это позволяет дополнительно контролировать различные уровни репозитория.
Вот пример, рассмотрим следующую структуру репозитория:
Repository
|-- Directory.Packages.props
|-- Solution1
|-- Directory.Packages.props
|-- Project1
|-- Solution2
|-- Project2
- Project1 будет оценивать файл
Directory.Packages.props
в каталогеRepository\Solution1\
, и он должен вручную импортировать следующий, если это необходимо.<Project> <Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Packages.props, $(MSBuildThisFileDirectory)..))" /> <ItemGroup> <PackageVersion Update="Newtonsoft.Json" Version="12.0.1" /> </ItemGroup> </Project>
- Project2 будет оценивать файл
Directory.Packages.props
в каталогеRepository\
.
Примечание. MSBuild не будет автоматически импортировать каждый Directory.Packages.props
для вас, только первый ближайший к проекту. Если у вас несколько Directory.Packages.props
, необходимо импортировать родительский элемент вручную, тогда как для корневого Directory.Packages.props
этого делать не потребуется.
Начало работы
Чтобы полностью подключить репозиторий, попробуйте выполнить следующие действия.
- Создайте новый файл в корне репозитория с именем
Directory.Packages.props
, который объявляет централизованно определенные версии пакетов и задает для свойства MSBuildManagePackageVersionsCentrally
значениеtrue
. - Объявите элементы
<PackageVersion />
вDirectory.Packages.props
. - Объявите в файлах проекта элементы
<PackageReference />
без атрибутовVersion
.
Обратитесь к нашему репозиторию образцов , чтобы получить представление о том, как может выглядеть централизованное управление пакетами.
Транзитивное закрепление
Вы можете автоматически переопределить транзитивную версию пакета даже без явного <PackageReference />
верхнего уровня, выбрав функцию, известную как транзитивное закрепление. Это повышает транзитивную зависимость до зависимости верхнего уровня от вашего имени, когда это необходимо.
Обратите внимание, что при транзитивном закреплении пакета допускается понижение. Если вы пытаетесь закрепить пакет до более низкой версии, чем запрошенная зависимостями, восстановление вызовет ошибку NU1109.
Эту функцию можно включить, задав свойство MSBuild CentralPackageTransitivePinningEnabled
true
в проекте или в файле импорта Directory.Packages.props
или Directory.Build.props
:
<PropertyGroup>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
Транзитивное закрепление и упаковка
При транзитивном закреплении пакета ваш проект использует более высокую версию, чем запрашивают зависимости. Если вы создаете пакет из вашего проекта, чтобы гарантировать его работоспособность, NuGet будет продвигать транзитивно закрепленные зависимости в явные зависимости в файле nuspec.
В следующем примере PackageA 1.0.0
имеет зависимость от PackageB 1.0.0
.
<Project>
<ItemGroup>
<PackageVersion Include="PackageA" Version="1.0.0" />
<PackageVersion Include="PackageB" Version="2.0.0" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="PackageA" />
</ItemGroup>
</Project>
При использовании команды пакета для создания пакета оба пакета будут отображаться в группе зависимостей.
<group targetFramework="net6.0">
<dependency id="PackageA" version="6.12.1" exclude="Build,Analyzers" />
<dependency id="PackageB" version="6.12.1" exclude="Build,Analyzers" />
</group>
Из-за этого при создании библиотеки следует тщательно оценить использование транзитивной привязки, так как это может привести к неожиданным зависимостям.
Переопределение версий пакетов
Вы можете переопределить отдельную версию пакета с помощью свойства VersionOverride
в элементе <PackageReference />
. Это переопределяет любые <PackageVersion />
, определенные централизованно.
<Project>
<ItemGroup>
<PackageVersion Include="PackageA" Version="1.0.0" />
<PackageVersion Include="PackageB" Version="2.0.0" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="PackageA" VersionOverride="3.0.0" />
</ItemGroup>
</Project>
Эту функцию можно отключить, задав свойство MSBuild CentralPackageVersionOverrideEnabled
false
в проекте или в файле импорта Directory.Packages.props
или Directory.Build.props
.
<PropertyGroup>
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
</PropertyGroup>
Если эта функция отключена, указание VersionOverride
для любого элемента <PackageReference />
приведет к ошибке во время восстановления, указывая, что эта функция отключена.
Отключение централизованного управления пакетами
Если вы хотите отключить централизованное управление пакетами для любого конкретного проекта, установите для свойства MSBuild ManagePackageVersionsCentrally
значение false
, чтобы его отключить.
<PropertyGroup>
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
</PropertyGroup>
Глобальные ссылки на пакеты
Заметка
Эта функция доступна только в Visual Studio 2022 17.4 или более поздней версии, пакет SDK для .NET 7.0.100.preview7 или более поздней версии, а также NuGet 6.4 или более поздней версии.
Глобальная ссылка на пакет используется для указания того, что пакет будет использоваться каждым проектом в репозитории. К ним относятся пакеты, которые выполняют управление версиями, расширяют сборку или другие пакеты, необходимые для всех проектов. Глобальные ссылки на пакеты добавляются в группу элементов PackageReference со следующими метаданными:
IncludeAssets="Runtime;Build;Native;contentFiles;Analyzers"
Это гарантирует, что пакет используется только в качестве зависимости разработки и предотвращает любые ссылки на сборки во время компиляции.PrivateAssets="All"
Это предотвращает использование глобальных ссылок пакетов подчиненными зависимостями.
Элементы GlobalPackageReference
должны размещаться в вашем Directory.Packages.props
, чтобы их мог использовать каждый проект в репозитории.
<Project>
<ItemGroup>
<GlobalPackageReference Include="Nerdbank.GitVersioning" Version="3.5.109" />
</ItemGroup>
</Project>
Предупреждение при использовании нескольких источников пакетов
При использовании централизованного управления пакетами вы увидите предупреждение NU1507
, если в конфигурации определено несколько источников пакетов. Чтобы устранить это предупреждение, сопоставите источники пакетов с сопоставлением источников пакетов или укажите один источник пакета.
There are 3 package sources defined in your configuration. When using central package management, please map your package sources with package source mapping (https://aka.ms/nuget-package-source-mapping) or specify a single package source.
Заметка
Централизованное управление пакетами активно разрабатывается. Мы благодарим вас за то, что вы попробовали, и ценим предоставление обратной связи на NuGet/Home.