Agent skill

dotnet-centralized-packages

Guide for Centralized Package Management (CPM) using Directory.Packages.props in .NET projects

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/dotnet-centralized-packages

SKILL.md

Centralized Package Management (CPM)

This skill provides guidance for using Central Package Management (CPM) with Directory.Packages.props in this .NET 10 project. CPM manages all NuGet package versions in one central location.

Table of Contents

  1. What is CPM
  2. Project Configuration
  3. Adding Packages
  4. Updating Packages
  5. Package Structure
  6. Troubleshooting
  7. Best Practices
  8. Quick Reference

What is CPM

Overview

Centralized Package Management (CPM) is a NuGet feature that centralizes package version management in a single Directory.Packages.props file at the solution root.

Benefits:

  • Single source of truth for package versions
  • No version conflicts across projects
  • Easier updates - change version in one place
  • Better dependency management
  • Simpler project files

How It Works

Traditional approach (NOT used in this project):

xml
<!-- Each .csproj specifies versions -->
<PackageReference Include="MSTest" Version="4.0.0-preview.25465.3" />

CPM approach (used in this project):

xml
<!-- Directory.Packages.props defines versions -->
<PackageVersion Include="MSTest" Version="4.0.0-preview.25465.3" />

<!-- .csproj references WITHOUT version -->
<PackageReference Include="MSTest" />

Project Configuration

Directory.Packages.props

Located at solution root (/Directory.Packages.props):

xml
<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
    <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
  </PropertyGroup>

  <ItemGroup Label="Core Packages">
    <PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.0-rc.2.25502.107" />
    <PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0-rc.2.25502.107" />
  </ItemGroup>

  <ItemGroup Label="Testing Packages">
    <PackageVersion Include="MSTest" Version="4.0.0-preview.25465.3" />
    <PackageVersion Include="Microsoft.Playwright.MSTest.v4" Version="1.55.0-beta-4" />
  </ItemGroup>
</Project>

Key Properties

ManagePackageVersionsCentrally: Enables CPM. All versions must be in Directory.Packages.props.

CentralPackageTransitivePinningEnabled: Pins transitive dependency versions to prevent unexpected updates.

Directory.Build.props Integration

CPM works alongside Directory.Build.props which defines shared MSBuild properties:

xml
<Project>
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>disable</Nullable>
    <ImplicitUsings>disable</ImplicitUsings>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  </PropertyGroup>
</Project>

Adding Packages

Step-by-Step Process

Step 1: Add version to Directory.Packages.props

xml
<ItemGroup Label="Your Category">
  <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

Step 2: Add reference to .csproj (WITHOUT version)

xml
<ItemGroup>
  <PackageReference Include="Newtonsoft.Json" />
</ItemGroup>

Examples from This Project

Adding MSTest (already in project):

xml
<!-- Directory.Packages.props -->
<PackageVersion Include="MSTest" Version="4.0.0-preview.25465.3" />

<!-- tests/ClaudeStack.Web.Tests/ClaudeStack.Web.Tests.csproj -->
<PackageReference Include="MSTest" />

Adding Razor Runtime Compilation (already in project):

xml
<!-- Directory.Packages.props -->
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.0-rc.2.25502.107" />

<!-- src/ClaudeStack.Web/ClaudeStack.Web.csproj -->
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" />

Common Mistakes

WRONG - Adding Version to .csproj:

xml
<!-- This will FAIL with CPM enabled -->
<PackageReference Include="MSTest" Version="4.0.0-preview.25465.3" />

Error message:

error NU1008: Version information is not allowed for central package versions.

CORRECT - No Version in .csproj:

xml
<PackageReference Include="MSTest" />

Using dotnet add package

When using dotnet add package, you MUST add the version separately:

bash
# Step 1: Add to Directory.Packages.props manually
# Edit Directory.Packages.props and add:
# <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />

# Step 2: Add reference to project
dotnet add src/ClaudeStack.Web/ClaudeStack.Web.csproj package Newtonsoft.Json

# OR manually add to .csproj:
# <PackageReference Include="Newtonsoft.Json" />

Note: dotnet add package may not automatically update Directory.Packages.props. Manual editing is often required.


Updating Packages

Update Single Package

Edit Directory.Packages.props:

xml
<!-- Before -->
<PackageVersion Include="MSTest" Version="4.0.0-preview.25465.3" />

<!-- After -->
<PackageVersion Include="MSTest" Version="4.0.0" />

This updates the package across all projects that reference it.

Update Multiple Packages

Edit versions in Directory.Packages.props. All projects will use the new versions automatically.

Update All Packages to Latest

bash
# List outdated packages
dotnet list package --outdated

# Update packages in Directory.Packages.props based on output
# (Manual process - edit Directory.Packages.props)

# Restore to apply changes
dotnet restore

Version Ranges (Not Recommended)

CPM supports version ranges, but not recommended for this project:

xml
<!-- Avoid this pattern -->
<PackageVersion Include="MSTest" Version="[4.0.0,5.0.0)" />

Use explicit versions for reproducibility.


Package Structure

Organizing with ItemGroup Labels

This project uses labeled ItemGroups for organization:

xml
<ItemGroup Label="Core Packages">
  <!-- ASP.NET Core packages -->
</ItemGroup>

<ItemGroup Label="Testing Packages">
  <!-- MSTest, Playwright, etc. -->
</ItemGroup>

<ItemGroup Label="Analysis Packages">
  <!-- Code analysis tools -->
</ItemGroup>

Labels are optional but improve readability.

Current Packages in Project

Core Packages:

  • Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation: 10.0.0-rc.2.25502.107
  • Microsoft.AspNetCore.OpenApi: 10.0.0-rc.2.25502.107

Testing Packages:

  • MSTest: 4.0.0-preview.25465.3
  • Microsoft.Playwright.MSTest.v4: 1.55.0-beta-4

Viewing All Packages

bash
# List all packages in solution
dotnet list package

# Include transitive dependencies
dotnet list package --include-transitive

Troubleshooting

Issue: "Version information is not allowed"

Full Error:

error NU1008: Version information is not allowed for central package versions.

Cause: PackageReference in .csproj includes Version attribute when CPM is enabled.

Solution: Remove Version from .csproj

xml
<!-- WRONG -->
<PackageReference Include="MSTest" Version="4.0.0-preview.25465.3" />

<!-- CORRECT -->
<PackageReference Include="MSTest" />

Issue: "Package not found" after adding to .csproj

Cause: Package version not defined in Directory.Packages.props.

Solution: Add to Directory.Packages.props:

xml
<PackageVersion Include="PackageName" Version="x.y.z" />

Issue: Different projects use different versions

Symptom: Project A uses v1.0, Project B uses v2.0 of same package.

Cause: With CPM, all projects must use the same version. This is by design.

Solutions:

  1. Preferred: Standardize on one version across all projects
  2. Workaround (not recommended): Disable CPM for specific packages using VersionOverride
xml
<!-- In .csproj, override version (not recommended) -->
<PackageReference Include="MSTest" VersionOverride="3.0.0" />

Issue: Transitive dependency conflicts

Symptom: Build errors about incompatible transitive dependencies.

Solution: Enable CentralPackageTransitivePinningEnabled:

xml
<PropertyGroup>
  <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>

Already enabled in this project.

Issue: dotnet add package doesn't work

Symptom: dotnet add package adds reference but version is missing from Directory.Packages.props.

Solution: Manually add version to Directory.Packages.props (this is expected behavior).

Issue: Restore fails after adding package

Solution: Ensure package exists on NuGet.org or configured feeds:

bash
# Clear NuGet cache
dotnet nuget locals all --clear

# Restore
dotnet restore

Best Practices

1. Always Edit Directory.Packages.props First

When adding a new package:

  1. Add <PackageVersion> to Directory.Packages.props
  2. Then add <PackageReference> to .csproj

2. Keep Versions Consistent

Avoid mixing preview and stable versions unnecessarily. This project uses preview packages because it targets .NET 10 RC 2.

3. Use Semantic Versioning

Understand version numbers: Major.Minor.Patch[-Prerelease]

  • 10.0.0-rc.2.25502.107: Major=10, Minor=0, Patch=0, Prerelease=rc.2.25502.107

4. Group Packages Logically

Use labeled ItemGroups:

  • Core Packages
  • Testing Packages
  • Analysis Packages
  • Development Packages

5. Review Transitive Dependencies

bash
dotnet list package --include-transitive

Understand what indirect dependencies your project uses.

6. Update Carefully

When updating packages:

  1. Test in development first
  2. Update one package at a time (for critical packages)
  3. Run full test suite after updates

7. Document Breaking Changes

When updating major versions, document breaking changes in commit messages or project documentation.

8. Avoid VersionOverride

Only use VersionOverride as a last resort. It defeats the purpose of CPM.


Quick Reference

File Locations

/Directory.Packages.props  - Package versions (central)
/Directory.Build.props     - Shared build properties
/**/*.csproj               - Package references (no versions)

Adding a Package

xml
<!-- Step 1: Directory.Packages.props -->
<PackageVersion Include="PackageName" Version="x.y.z" />

<!-- Step 2: ProjectFile.csproj -->
<PackageReference Include="PackageName" />

Updating a Package

xml
<!-- Directory.Packages.props - change version -->
<PackageVersion Include="PackageName" Version="x.y.z" />

<!-- All projects automatically use new version -->

Common Commands

bash
# List packages
dotnet list package

# List outdated packages
dotnet list package --outdated

# List transitive dependencies
dotnet list package --include-transitive

# Restore packages
dotnet restore

# Clear cache and restore
dotnet nuget locals all --clear && dotnet restore

Directory.Packages.props Template

xml
<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
    <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
  </PropertyGroup>

  <ItemGroup Label="Category Name">
    <PackageVersion Include="PackageName" Version="x.y.z" />
  </ItemGroup>
</Project>

Error Reference

Error Cause Solution
NU1008 Version in .csproj Remove Version attribute
Package not found Missing from Directory.Packages.props Add PackageVersion
Version conflict Different versions needed Use single version or VersionOverride

Related Skills

  • mstest-testing-platform: MSTest package configuration and usage
  • playwright-dotnet: Playwright package setup and testing
  • dotnet-cli-essentials: Package commands (list, add, restore)

Additional Resources


Version Information

This project uses:

  • .NET SDK: 10.0.100-rc.2.25502.107
  • NuGet CPM: Supported in .NET 6.0+ SDK
  • MSBuild: 17.0+

CPM is a stable NuGet feature as of .NET 6.0 SDK.

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results