依赖项管理是 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 文件。
如果有多个此类文件,则必须根据需要手动导入父文件。
入门
若要完全载入存储库,请执行以下步骤:
- 在名为
Directory.Packages.props的存储库的根目录中创建一个新文件,声明集中定义的包版本,并将 MSBuild 属性ManagePackageVersionsCentrally设置为true。 - 在
<PackageVersion />中声明Directory.Packages.props项目。 - 在你的项目文件中声明没有
<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 设置为在项目或 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>
使用 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 设置为在项目或 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 或更高版本、.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.