NuGet包管理技能Skill package-management

本技能详细介绍了如何使用dotnet CLI命令和中央包管理(CPM)高效管理.NET项目的NuGet包。内容包括:避免直接编辑XML的黄金法则、CPM的启用与配置、共享版本变量的使用、常见CLI命令参考、包源管理、故障排除方法以及反模式警示。适用于.NET开发者在添加、删除、更新包,管理多项目版本一致性,以及解决包冲突时参考。关键词:NuGet包管理、dotnet CLI、中央包管理CPM、.NET开发、包版本控制、依赖管理。

后端开发 0 次安装 0 次浏览 更新于 2/26/2026

name: package-management description: 使用中央包管理(CPM)和 dotnet CLI 命令管理 NuGet 包。切勿直接编辑 XML - 使用 dotnet add/remove/list 命令。对相关包使用共享版本变量。 invocable: false

NuGet 包管理

何时使用此技能

在以下情况下使用此技能:

  • 添加、删除或更新 NuGet 包
  • 为解决方案设置中央包管理(CPM)
  • 跨多个项目管理包版本
  • 排查包冲突或还原问题

黄金法则:切勿直接编辑 XML

始终使用 dotnet CLI 命令管理包。 切勿手动编辑 .csprojDirectory.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" />

共享版本变量

使用共享版本变量对相关包进行分组:

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>

  <!-- 共享版本变量 -->
  <PropertyGroup Label="SharedVersions">
    <AkkaVersion>1.5.59</AkkaVersion>
    <AkkaHostingVersion>1.5.59</AkkaHostingVersion>
    <AspireVersion>9.0.0</AspireVersion>
    <OpenTelemetryVersion>1.11.0</OpenTelemetryVersion>
    <XunitVersion>2.9.2</XunitVersion>
  </PropertyGroup>

  <!-- Akka.NET 包 - 全部使用相同版本 -->
  <ItemGroup Label="Akka.NET">
    <PackageVersion Include="Akka" Version="$(AkkaVersion)" />
    <PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />
    <PackageVersion Include="Akka.Cluster.Sharding" Version="$(AkkaVersion)" />
    <PackageVersion Include="Akka.Cluster.Tools" Version="$(AkkaVersion)" />
    <PackageVersion Include="Akka.Persistence" Version="$(AkkaVersion)" />
    <PackageVersion Include="Akka.Streams" Version="$(AkkaVersion)" />
    <PackageVersion Include="Akka.Hosting" Version="$(AkkaHostingVersion)" />
    <PackageVersion Include="Akka.Cluster.Hosting" Version="$(AkkaHostingVersion)" />
  </ItemGroup>

  <!-- Aspire 包 -->
  <ItemGroup Label="Aspire">
    <PackageVersion Include="Aspire.Hosting" Version="$(AspireVersion)" />
    <PackageVersion Include="Aspire.Hosting.AppHost" Version="$(AspireVersion)" />
    <PackageVersion Include="Aspire.Hosting.PostgreSQL" Version="$(AspireVersion)" />
    <PackageVersion Include="Aspire.Hosting.Testing" Version="$(AspireVersion)" />
  </ItemGroup>

  <!-- OpenTelemetry 包 -->
  <ItemGroup Label="OpenTelemetry">
    <PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="$(OpenTelemetryVersion)" />
    <PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="$(OpenTelemetryVersion)" />
    <PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="$(OpenTelemetryVersion)" />
    <PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="$(OpenTelemetryVersion)" />
  </ItemGroup>

  <!-- 测试 -->
  <ItemGroup Label="Testing">
    <PackageVersion Include="xunit" Version="$(XunitVersion)" />
    <PackageVersion Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
    <PackageVersion Include="FluentAssertions" Version="6.12.0" />
    <PackageVersion Include="Verify.Xunit" Version="26.0.0" />
  </ItemGroup>
</Project>

好处:

  • 通过更改一个变量更新所有 Akka 包
  • 使用带标签的 ItemGroup 清晰组织
  • 防止相关包中的版本不匹配

何时不应使用 CPM

中央包管理并非总是正确的选择:

遗留项目

将现有大型解决方案迁移到 CPM 可能会引入问题:

  • 现有的版本冲突会一次性全部显现
  • 某些包可能有故意的版本差异
  • 迁移需要同时修改许多文件

建议:对于遗留项目,逐步迁移,或者如果现有方案有效,则坚持使用按项目版本管理。

版本范围

CPM 需要精确版本 - 不支持版本范围:

<!-- CPM 不支持 -->
<PackageVersion Include="Newtonsoft.Json" Version="[13.0,14.0)" />

<!-- 必须使用精确版本 -->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />

如果您需要版本范围(很少见,但某些库场景需要),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

对于特定于解决方案的源,创建 NuGet.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
    <add key="MyPrivateFeed" value="https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <MyPrivateFeed>
      <add key="Username" value="az" />
      <add key="ClearTextPassword" value="%NUGET_PAT%" />
    </MyPrivateFeed>
  </packageSourceCredentials>
</configuration>

常见模式

仅开发包

<!-- Directory.Packages.props -->
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />

<!-- 项目文件 - 标记为开发依赖项 -->
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />

条件包

<!-- 仅在 Debug 构建中包含 -->
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
  <PackageReference Include="JetBrains.Annotations" />
</ItemGroup>

<!-- 平台特定 -->
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
  <PackageReference Include="System.Text.Json" />
</ItemGroup>

版本覆盖(逃生舱口)

当必须为一个项目覆盖 CPM 时(罕见):

<!-- 项目文件 - 谨慎使用! -->
<PackageReference Include="Newtonsoft.Json" VersionOverride="12.0.3" />

警告:这会被 Slopwatch(参见 dotnet/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 -->
<PropertyGroup>
  <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>

然后提交 packages.lock.json 文件。


反模式

不要:直接编辑 XML

<!-- 错误:手动编辑 XML -->
<PackageReference Include="Typo.Package" Version="1.0.0" />
<!-- 包可能不存在!CLI 会捕获此错误。 -->

不要:使用 CPM 时内联版本

<!-- 错误:绕过 CPM -->
<PackageReference Include="Serilog" Version="4.0.0" />

<!-- 正确:版本来自 Directory.Packages.props -->
<PackageReference Include="Serilog" />

不要:混合版本管理

<!-- 错误:一些版本在 CPM 中,一些内联 -->
<PackageReference Include="Serilog" />  <!-- 来自 CPM -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />  <!-- 内联 -->

不要:忘记共享变量

<!-- 错误:相关包使用不同版本 -->
<PackageVersion Include="Akka" Version="1.5.59" />
<PackageVersion Include="Akka.Cluster" Version="1.5.58" />  <!-- 不匹配! -->

<!-- 正确:使用共享变量 -->
<PackageVersion Include="Akka" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />

快速参考

任务 命令
添加包 dotnet add package <名称>
添加特定版本 dotnet add package <名称> --version <版本>
删除包 dotnet remove package <名称>
列出包 dotnet list package
显示过时的包 dotnet list package --outdated
显示易受攻击的包 dotnet list package --vulnerable
还原 dotnet restore
清除缓存 dotnet nuget locals all --clear

资源