Documentation
Centralized Package Management
Overview
The repository uses Central Package Management (CPM) to manage all NuGet package versions from a single Directory.Packages.props file located at the repository root. This provides:
- ✅ Single source of truth for all package versions
- ✅ Consistent versions across all projects
- ✅ Easier dependency updates (change once, applies everywhere)
- ✅ Reduced version conflicts
- ✅ Better security (easier to track and update vulnerable packages)
Structure
/home/runner/work/ad-blocking/ad-blocking/
├── Directory.Build.props # Global MSBuild properties
├── Directory.Packages.props # ⭐ CENTRALIZED PACKAGE VERSIONS
└── src/
├── adguard-api-dotnet/
│ └── src/
│ ├── AdGuard.ApiClient/AdGuard.ApiClient.csproj
│ ├── AdGuard.ConsoleUI/AdGuard.ConsoleUI.csproj
│ └── ... (all reference packages without versions)
└── rules-compiler-dotnet/
└── src/
└── ... (all reference packages without versions)
How It Works
Root Configuration (Directory.Packages.props)
The root-level Directory.Packages.props file defines all package versions:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Polly" Version="8.6.5" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.1" />
<!-- ... all other packages -->
</ItemGroup>
</Project>
Project Files (.csproj)
Individual projects reference packages without specifying versions:
<ItemGroup>
<!-- ✅ Correct: No Version attribute -->
<PackageReference Include="Polly" />
<PackageReference Include="Microsoft.Extensions.Logging" />
</ItemGroup>
DON'T specify versions in project files:
<ItemGroup>
<!-- ❌ Wrong: Version will conflict with CPM -->
<PackageReference Include="Polly" Version="8.6.5" />
</ItemGroup>
Package Categories
Core API Client Dependencies
JsonSubTypes- JSON polymorphic serializationNewtonsoft.Json- JSON serializationPolly- Resilience and transient fault handling
Microsoft.Extensions (v10.0.1)
All Microsoft.Extensions packages are standardized to version 10.0.1 (latest for .NET 10):
- Configuration (base, abstractions, JSON, environment variables, user secrets, command line)
- Dependency Injection (base, abstractions)
- Hosting
- Logging (base, abstractions, console)
- Options (base, configuration extensions)
Entity Framework Core (v9.0.0)
Microsoft.EntityFrameworkCore(base)Microsoft.EntityFrameworkCore.DesignMicrosoft.EntityFrameworkCore.InMemory(testing)Microsoft.EntityFrameworkCore.SqliteMicrosoft.EntityFrameworkCore.SqlServerNpgsql.EntityFrameworkCore.PostgreSQL
UI Dependencies
Spectre.Console- Console UI framework
Rules Compiler Dependencies
YamlDotNet- YAML parsingTomlyn- TOML parsing
PowerShell Dependencies
PowerShellStandard.Library- PowerShell module development
Testing Dependencies
xunit(v2.9.3) - Test frameworkxunit.runner.visualstudio(v3.1.5) - Test runnerMicrosoft.NET.Test.Sdk(v18.0.1) - Test SDKMoq(v4.20.72) - Mocking frameworkFluentAssertions(v6.12.1) - Assertion librarycoverlet.collector(v6.0.4) - Code coverage
Benchmark Dependencies
BenchmarkDotNet(v0.15.8)BenchmarkDotNet.Diagnostics.Windows(v0.15.8)Microsoft.VisualStudio.DiagnosticsHub.BenchmarkDotNetDiagnosers(v18.0.36525.3)
Common Tasks
Adding a New Package
-
Add version to
Directory.Packages.props:<PackageVersion Include="NewPackage" Version="1.2.3" /> -
Reference in project file (without version):
<PackageReference Include="NewPackage" /> -
Restore packages:
dotnet restore
Updating a Package Version
-
Update version in
Directory.Packages.propsonly:<!-- Before --> <PackageVersion Include="Polly" Version="8.6.5" /> <!-- After --> <PackageVersion Include="Polly" Version="8.7.0" /> -
All projects automatically use the new version after restore:
dotnet restore
Checking Package Versions
View all centralized package versions:
cat Directory.Packages.props
Check what version a project is using:
dotnet list package
Troubleshooting
Error: "Package 'X' doesn't have a version defined"
Cause: Package is referenced in a .csproj file but not defined in Directory.Packages.props.
Solution: Add the package version to Directory.Packages.props:
<PackageVersion Include="X" Version="1.0.0" />
Error: "Version conflict detected"
Cause: Project file has explicit Version attribute on <PackageReference>.
Solution: Remove the Version attribute from the project file:
<!-- Before (wrong) -->
<PackageReference Include="Polly" Version="8.6.5" />
<!-- After (correct) -->
<PackageReference Include="Polly" />
Build fails after CPM migration
-
Clean the solution:
dotnet clean -
Restore packages:
dotnet restore -
Build again:
dotnet build
Version Consistency Rules
- Microsoft.Extensions packages: All should use the same version (currently 10.0.1)
- Entity Framework Core packages: All should use the same version (currently 9.0.0)
- Test packages: Keep xunit, Moq, and test SDK versions aligned
- Benchmark packages: Keep BenchmarkDotNet packages at the same version
Migration History
Before: Three separate Directory.Packages.props files:
src/adguard-api-dotnet/src/Directory.Packages.propssrc/adguard-api-dotnet/src/api-client/Directory.Packages.propssrc/rules-compiler-dotnet/Directory.Packages.props
Issues:
- Duplicate definitions
- Version inconsistencies (Microsoft.Extensions: v9.0.0 vs v10.0.1)
- Some projects used explicit versions in
.csprojfiles
After: Single root-level Directory.Packages.props
- All packages centralized
- All versions consistent
- All projects reference packages without versions