package-management by aaronontheweb/dotnet-skills
npx skills add https://github.com/aaronontheweb/dotnet-skills --skill package-management在以下情况使用此技能:
始终使用 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" />
原因:
CPM 将所有包版本集中在一个文件中,消除了跨项目的版本冲突。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
在解决方案根目录创建 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>
项目引用包时不带版本号:
<!-- src/MyApp/MyApp.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="Serilog" />
</ItemGroup>
</Project>
# 添加到 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>
优点:
中央包管理并非总是正确的选择:
将现有的大型解决方案迁移到 CPM 可能会引入问题:
建议:对于遗留项目,逐步迁移,或者如果现有方式有效,则坚持使用按项目版本管理。
CPM 需要确切的版本 - 不支持版本范围:
<!-- CPM 不支持 -->
<PackageVersion Include="Newtonsoft.Json" Version="[13.0,14.0)" />
<!-- 必须使用确切版本 -->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
如果你需要版本范围(很少见,但某些库场景需要),CPM 将无法工作。
CPM 要求:
如果你的目标 SDK 版本较旧,或者团队成员使用较旧的工具,CPM 可能会导致构建失败。
如果你的解决方案跨越多个独立构建的仓库,CPM 的单个 Directory.Packages.props 将无济于事 - 每个仓库都需要自己的配置文件。
# 添加最新稳定版本
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:
<?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 -->
<PackageReference Include="Typo.Package" Version="1.0.0" />
<!-- 包可能不存在!CLI 会捕获此错误。 -->
<!-- 错误:绕过 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 <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 |
每周安装量
105
仓库
GitHub 星标数
500
首次出现
2026年1月28日
安全审计
安装于
claude-code79
codex63
github-copilot61
opencode61
gemini-cli57
kimi-cli55
Use this skill when:
Always usedotnet CLI commands to manage packages. Never manually edit .csproj or Directory.Packages.props files.
# DO: Use CLI commands
dotnet add package Newtonsoft.Json
dotnet remove package Newtonsoft.Json
dotnet list package --outdated
# DON'T: Edit XML directly
# <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
Why:
CPM centralizes all package versions in one file, eliminating version conflicts across projects.
Create Directory.Packages.props in solution root:
<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>
Projects reference packages without versions :
<!-- src/MyApp/MyApp.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="Serilog" />
</ItemGroup>
</Project>
# Adds to Directory.Packages.props AND project file
dotnet add package Serilog.Sinks.Console
# Result in Directory.Packages.props:
# <PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
# Result in project file:
# <PackageReference Include="Serilog.Sinks.Console" />
Group related packages with shared version variables:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<!-- Shared version variables -->
<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 packages - all use same version -->
<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 packages -->
<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 packages -->
<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>
<!-- Testing -->
<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>
Benefits:
Central Package Management isn't always the right choice:
Migrating an existing large solution to CPM can introduce issues:
Recommendation : For legacy projects, migrate incrementally or stick with per-project versioning if it's working.
CPM requires exact versions - it doesn't support version ranges:
<!-- NOT supported with CPM -->
<PackageVersion Include="Newtonsoft.Json" Version="[13.0,14.0)" />
<!-- Must use exact version -->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
If you need version ranges (rare, but some library scenarios require it), CPM won't work.
CPM requires:
If you're targeting older SDK versions or have team members on older tooling, CPM may cause build failures.
If your solution spans multiple repositories that are built independently, CPM's single Directory.Packages.props won't help - each repo needs its own.
# Add latest stable version
dotnet add package Serilog
# Add specific version
dotnet add package Serilog --version 4.0.0
# Add prerelease
dotnet add package Serilog --prerelease
# Add to specific project
dotnet add src/MyApp/MyApp.csproj package Serilog
# Remove from current project
dotnet remove package Serilog
# Remove from specific project
dotnet remove src/MyApp/MyApp.csproj package Serilog
# List all packages in solution
dotnet list package
# Show outdated packages
dotnet list package --outdated
# Include transitive dependencies
dotnet list package --include-transitive
# Show vulnerable packages
dotnet list package --vulnerable
# Show deprecated packages
dotnet list package --deprecated
# With CPM: Edit the version in Directory.Packages.props
# Then restore to apply
dotnet restore
# Without CPM: Remove and add with new version
dotnet remove package Serilog
dotnet add package Serilog --version 4.1.0
# Or use dotnet-outdated tool (recommended)
dotnet tool install --global dotnet-outdated-tool
dotnet outdated --upgrade
# Restore packages
dotnet restore
# Clear local cache (troubleshooting)
dotnet nuget locals all --clear
# Force restore (ignore cache)
dotnet restore --force
dotnet nuget list source
# Add authenticated feed
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
For solution-specific sources, create 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" />
<!-- Project file - mark as development dependency -->
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<!-- Only include in Debug builds -->
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<PackageReference Include="JetBrains.Annotations" />
</ItemGroup>
<!-- Platform-specific -->
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="System.Text.Json" />
</ItemGroup>
When you must override CPM for one project (rare):
<!-- Project file - use sparingly! -->
<PackageReference Include="Newtonsoft.Json" VersionOverride="12.0.3" />
Warning : This is detected by Slopwatch (see dotnet/slopwatch skill) as potential slop.
# See full dependency tree
dotnet list package --include-transitive
# Find what's pulling in a specific package
dotnet list package --include-transitive | grep -i "PackageName"
# Clear all caches
dotnet nuget locals all --clear
# Restore with detailed logging
dotnet restore --verbosity detailed
# Check for locked packages
cat packages.lock.json
For reproducible builds, use package lock files:
<!-- Directory.Build.props -->
<PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
Then commit packages.lock.json files.
<!-- BAD: Manual XML editing -->
<PackageReference Include="Typo.Package" Version="1.0.0" />
<!-- Package might not exist! CLI would catch this. -->
<!-- BAD: Bypasses CPM -->
<PackageReference Include="Serilog" Version="4.0.0" />
<!-- GOOD: Version comes from Directory.Packages.props -->
<PackageReference Include="Serilog" />
<!-- BAD: Some versions in CPM, some inline -->
<PackageReference Include="Serilog" /> <!-- From CPM -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <!-- Inline -->
<!-- BAD: Related packages with different versions -->
<PackageVersion Include="Akka" Version="1.5.59" />
<PackageVersion Include="Akka.Cluster" Version="1.5.58" /> <!-- Mismatch! -->
<!-- GOOD: Use shared variable -->
<PackageVersion Include="Akka" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />
| Task | Command |
|---|---|
| Add package | dotnet add package <name> |
| Add specific version | dotnet add package <name> --version <ver> |
| Remove package | dotnet remove package <name> |
| List packages | dotnet list package |
| Show outdated | dotnet list package --outdated |
| Show vulnerable | dotnet list package --vulnerable |
Weekly Installs
105
Repository
GitHub Stars
500
First Seen
Jan 28, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
claude-code79
codex63
github-copilot61
opencode61
gemini-cli57
kimi-cli55
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
116,600 周安装
| Restore | dotnet restore |
| Clear cache | dotnet nuget locals all --clear |