用途
该技能用于在 .NET 项目中管理 NuGet 包,适用于以下场景:添加、移除或更新 NuGet 包;为解决方案设置中央包管理(CPM);跨多个项目管理包版本;排查包冲突或还原(restore)问题。
核心原则:绝不直接编辑 XML
始终使用 dotnet CLI 命令管理包,绝不手动编辑 .csproj 或 Directory.Packages.props 文件。
应使用 CLI 命令:
dotnet add package Newtonsoft.Json
dotnet remove package Newtonsoft.Json
dotnet list package --outdated
不应直接编辑 XML:
# <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
原因:CLI 会验证包是否存在并解析正确版本;正确处理传递依赖;在存在锁文件时更新锁文件;避免拼写错误和格式错误的 XML;与 CPM 正确配合。
中央包管理(CPM)
CPM 将所有包版本集中到一个文件中,消除跨项目的版本冲突。
启用 CPM:在解决方案根目录创建 Directory.Packages.props:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Serilog" Version="4.0.0" />
<PackageVersion Include="xunit" Version="2.9.2" />
</ItemGroup>
</Project>
使用 CPM 的项目文件引用包时不带版本:
<!-- src/MyApp/MyApp.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="Serilog" />
</ItemGroup>
</Project>
使用 CPM 添加包:
# 同时添加到 Directory.Packages.props 和项目文件
dotnet add package Serilog.Sinks.Console
结果:Directory.Packages.props 中新增 <PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />,项目文件中新增 <PackageReference Include="Serilog.Sinks.Console" />。
共享版本变量:可将相关包分组并使用共享版本变量,例如为 Akka.NET、Aspire、OpenTelemetry、测试等分别定义变量与带标签的 ItemGroup,从而通过修改一个变量更新所有相关包,防止相关包版本不匹配。
何时不使用 CPM
- 遗留项目:将现有大型解决方案迁移到 CPM 可能引入问题(现有版本冲突会一次性暴露、某些包可能有意的版本差异、迁移需同时改动大量文件)。建议增量迁移,或若按项目版本管理运行良好则保持现状。
- 版本范围:CPM 要求精确版本,不支持版本范围。若需要版本范围(少见,但某些库场景需要),CPM 不适用。
- 较旧的 .NET 版本:CPM 需要 .NET SDK 6.0.300+、NuGet 6.2+、Visual Studio 2022 17.2+。若面向较旧 SDK 或团队成员使用较旧工具,CPM 可能导致构建失败。
- 多仓库解决方案:若解决方案跨越多个独立构建的仓库,CPM 的单一 Directory.Packages.props 无法覆盖,每个仓库需要各自的配置。
CLI 命令参考
添加包:
dotnet add package Serilog
dotnet add package Serilog --version 4.0.0
dotnet add package Serilog --prerelease
dotnet add src/MyApp/MyApp.csproj package Serilog
移除包:
dotnet remove package Serilog
dotnet remove src/MyApp/MyApp.csproj package Serilog
列出包:
dotnet list package
dotnet list package --outdated
dotnet list package --include-transitive
dotnet list package --vulnerable
dotnet list package --deprecated
更新包:
# 使用 CPM:编辑 Directory.Packages.props 中的版本,然后还原
dotnet restore
# 不使用 CPM:移除后以新版本添加
dotnet remove package Serilog
dotnet add package Serilog --version 4.1.0
# 或使用 dotnet-outdated 工具(推荐)
dotnet tool install --global dotnet-outdated-tool
dotnet outdated --upgrade
还原与清理:
dotnet restore
dotnet nuget locals all --clear
dotnet restore --force
包源
列出源:dotnet nuget list source
添加私有源:
dotnet nuget add source https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json \
--name MyFeed \
--username az \
--password $PAT \
--store-password-in-clear-text
NuGet.config:可为解决方案创建专属源配置,包含 packageSources 与 packageSourceCredentials 节点。
常见模式
- 仅开发用包:在项目文件中标记
PrivateAssets="All"。 - 条件包:使用 ItemGroup Condition 按配置(如 Debug)或目标框架包含包。
- 版本覆盖(逃生舱):在项目文件中使用
VersionOverride,需谨慎使用;该做法会被 Slopwatch 检测为潜在 slop。
排查问题
版本冲突:
dotnet list package --include-transitive
dotnet list package --include-transitive | grep -i "PackageName"
还原失败:
dotnet nuget locals all --clear
dotnet restore --verbosity detailed
cat packages.lock.json
锁文件:为实现可复现构建,可在 Directory.Build.props 中设置 <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>,然后提交 packages.lock.json 文件。
反模式
- 不要直接编辑 XML:手动编辑可能引用不存在的包,CLI 可捕获此类问题。
- 不要在 CPM 下内联版本:
<PackageReference Include="Serilog" Version="4.0.0" />会绕过 CPM。 - 不要混用版本管理:部分版本来自 CPM、部分内联。
- 不要忘记共享变量:相关包应使用同一变量,避免版本不匹配。
快速参考
| 任务 | 命令 |
|---|---|
| 添加包 | dotnet add package <name> |
| 添加指定版本 | dotnet add package <name> --version <ver> |
| 移除包 | dotnet remove package <name> |
| 列出包 | dotnet list package |
| 显示过时包 | dotnet list package --outdated |
| 显示有漏洞的包 | dotnet list package --vulnerable |
| 还原 | dotnet restore |
| 清理缓存 | dotnet nuget locals all --clear |
资源
- Central Package Management: https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management
- dotnet CLI Reference: https://learn.microsoft.com/en-us/dotnet/core/tools/
- NuGet.config Reference: https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file