中央包管理(CPM)

依赖项管理是 NuGet 的核心功能。 尽管管理单个项目的依赖项非常简单,但随着解决方案中的项目数量的增长,它变得越来越复杂。

如果管理许多不同的项目的常见依赖项,则可以利用 NuGet 的中央包管理 (CPM) 功能从单个中心位置执行所有这些作。

中央包管理适用于所有 <PackageReference>基于 MSBuild 的项目(包括 旧版 CSPROJ)。

启用中央软件包管理

若要开始使用中央包管理,请在存储库的根目录中创建一个 Directory.Packages.props 文件,并将 MSBuild 属性 ManagePackageVersionsCentrally 设置为 true

可以手动创建它,或使用 .NET CLI:

dotnet new packagesprops

在内部 Directory.Packages.props,定义 <PackageVersion /> 元素以指定项目使用的包 ID 和版本。

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="PackageA" Version="1.0.0" />
    <PackageVersion Include="PackageB" Version="2.0.0" />
  </ItemGroup>
</Project>

在每个项目文件中,定义 <PackageReference /> 不带特性的 Version 元素。 版本将从相应的 <PackageVersion /> 条目中 Directory.Packages.props解析。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="PackageA" />
  </ItemGroup>
</Project>

现在,你正在使用中央包管理和在中心位置管理版本!

中央包管理规则

该文件 Directory.Packages.props 具有有关其位置和上下文在存储库中的特定规则。 默认情况下,仅计算给定项目的一 Directory.Packages.props 个文件。

如果存储库中有多个 Directory.Packages.props 文件,则会评估离给定项目的目录最近的文件。 这允许在存储库的各个级别进行额外的控制。

请考虑以下存储库目录结构:

📂 (root)
 ├─📄 Directory.Packages.props
 |
 ├─📂Solution1
 |  ├─ 📄Directory.Packages.props
 |  |
 |  └─ 📂 Project1
 |      └─📄Project1.csproj
 |
 └─ 📂 Solution2
    └─ 📂 Project2
        └─ 📄 Project2.csproj

Project1.csproj Directory.Packages.props将使用目录中的文件Repository\Solution1\。 如果要包含父级的 Directory.Packages.props设置,则必须手动导入它。

<Project>
  <Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Packages.props, $(MSBuildThisFileDirectory)..))" />
  <ItemGroup>
    <PackageVersion Update="Newtonsoft.Json" Version="12.0.1" />
  </ItemGroup>
</Project>

Project2.csproj 将评估 Directory.Packages.props 根目录中的文件。

注意

MSBuild 只会自动导入在项目目录或任何父目录中找到的第一个 Directory.Packages.props 文件。 如果有多个此类文件,则必须根据需要手动导入父文件。

入门

若要完全载入存储库,请执行以下步骤:

  1. 在名为 Directory.Packages.props 的存储库的根目录中创建一个新文件,声明集中定义的包版本,并将 MSBuild 属性 ManagePackageVersionsCentrally 设置为 true
  2. <PackageVersion />中声明 Directory.Packages.props 项目。
  3. 在你的项目文件中声明没有 <PackageReference /> 属性的 Version 项目。

有关中央包管理的外观示例,请参阅示例 存储库

对不同目标框架使用不同的版本

随着 NuGet 包的发展,包所有者可能会放弃对较旧的目标框架的支持。 这可能会导致库开发人员出现问题,这些库仍面向较旧的框架,但想要为较新的目标框架引用较新版本的包。

例如,如果项目面向 .NET Standard 2.0、.NET 8.0 和 .NET Framework 4.7.2,但 PackageA 在其最新版本中不再支持 .NET Standard 2.0,则可以为每个目标框架指定不同的版本。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;net8.0;net472</TargetFrameworks>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="PackageA" />
  </ItemGroup>
</Project>

在这种情况下,请使用 Directory.Packages.props为每个目标框架定义不同的版本:

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="PackageA" Version="1.0.0" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
    <PackageVersion Include="PackageA" Version="2.0.0" Condition="'$(TargetFramework)' == 'net8.0' Or '$(TargetFramework)' == 'net472'" />
  </ItemGroup>
</Project>

可传递固定

可以通过选择加入称为可传递固定的功能来自动替代不带显式顶级 <PackageReference /> 项的可传递包版本。 这将在必要时以隐式方式将可传递依赖项提升为顶级依赖项。

请注意,在传递固定包时不允许降级。 如果尝试将包固定到低于依赖项请求的版本,还原将引发 NU1109 错误。

可以通过将 MSBuild 属性 CentralPackageTransitivePinningEnabled 设置为在项目或 trueDirectory.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>

使用 pack 命令创建包时,这两个包将显示在依赖项组中。

<group targetFramework="net6.0">
  <dependency id="PackageA" version="1.0.0" exclude="Build,Analyzers" />
  <dependency id="PackageB" version="2.0.0" 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 设置为在项目或 falseDirectory.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 或更高版本、.NET SDK 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 警告

使用中央包管理时,如果在配置中定义了多个包源,NuGet 将记录警告 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.