Tag: NuGet

.NETDevelopmentVisual Studio

Centralizing NuGet Package Versions with Central Package Management

In my Running and Building Azure Functions with Modern .NET talk this week at the Mississauga .NET User Group, one of the topics that consistently gets a reaction from the audience is Central Package Management (CPM). Once I show people what it does, the reaction is almost always the same: “I didn’t know this existed — I need to go add this to all my solutions.”

This post is the written companion to that section of the talk. If you’ve ever dealt with the pain of keeping NuGet package versions in sync across a large solution, CPM is going to be immediately relevant to you.

What is Central Package Management?

Central Package Management is a built-in .NET feature that lets you define all NuGet package versions in a single place — a Directory.Packages.props file at the solution root — rather than scattering Version attributes across individual .csproj files.

Here’s a simple example of what that file looks like:

<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.Azure.Functions.Worker" Version="2.0.0" />
<PackageVersion Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.3.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

And in your individual .csproj files, you simply reference the package without a version:

<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Worker" />
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>

The version is automatically resolved from the central file. Clean, simple, and immediately obvious what version you’re on when you look at the central file.

Why This Matters

In a solution with many projects, keeping package versions in sync manually is error-prone. You end up with Project A on Newtonsoft.Json 13.0.1 and Project B on 13.0.3 without anyone really noticing until a subtle runtime difference bites you. CPM solves this by making version drift impossible — there’s one place to look and one place to change.

Benefits at a glance:

  • Single source of truth for all package versions in the solution
  • Eliminates version drift across projects
  • Cleaner .csproj files — no version attributes cluttering your package references
  • Supports both direct and transitive dependency version control

Manually Migrate an Existing Solution to CPM

If you already have a solution with a bunch of projects, migrating to CPM is straightforward but can be tedious to do by hand across many .csproj files. Here’s the approach:

Step 1: Create Directory.Packages.props

At the root of your solution, create a Directory.Packages.props file with ManagePackageVersionsCentrally set to true and consolidate all your package versions as <PackageVersion> entries:

<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="PackageName" Version="x.y.z" />
<!-- add all packages here -->
</ItemGroup>
</Project>

Step 2: Remove Versions from Project Files

Strip the Version attribute from every <PackageReference> in your .csproj files. If you have many projects, do this with the CentralisedPackageConverter CLI tool (covered below) — don’t do it by hand.

Step 3: Validate and Build

Build your solution and confirm everything resolves correctly. Pay attention to any packages that may have conflicting versions across projects — those will need a conscious decision about which version to standardize on.

This is great, but there must be a better way. Let’s take a look at a community tool that automates this process.

Using the CentralisedPackageConverter CLI Tool

The best way to handle the migration for an existing solution is the CentralisedPackageConverter CLI tool, which automates the tedious parts:

# Install the tool globally
dotnet tool install CentralisedPackageConverter --global
# Run the conversion against your solution folder
central-pkg-converter /path/to/your/solution/folder

The tool will:

  • Scan all .csproj files in the solution
  • Generate a Directory.Packages.props with all discovered versions
  • Remove version attributes from individual project files

I highly recommend using this over a manual migration. It’s fast and reduces the chance of missing something.

Let’s try this out.

We now have a Directory.Packages.props with all discovered versions:

And if we look in our project files, the versions are removed:

Advanced Features


Once you’re on CPM, there are a few additional capabilities worth knowing about.

Overriding Versions per Project

There are situations where a specific project needs a different version of a package than the rest of the solution — say, a legacy integration that can’t move to the latest version yet. CPM handles this with VersionOverride in the individual project file:

<PackageReference Include="SomePackage" VersionOverride="1.2.3" />

Use this sparingly. Its presence in a project file is a signal that something needs attention.

Different Versions per Target Framework

If you have a multi-targeted project, you can conditionally apply different versions by target framework using standard MSBuild conditions within Directory.Packages.props:

<PackageVersion Include="SomePackage" Version="2.0.0" Condition="'$(TargetFramework)' == 'net10.0'" />
<PackageVersion Include="SomePackage" Version="1.5.0" Condition="'$(TargetFramework)' == 'net8.0'" />

Transitive Pinning

This one quietly solves a very real problem. Version drift caused by transitive dependencies — packages your packages depend on — is easy to miss and can cause subtle compatibility issues. CPM supports pinning transitive dependencies centrally, so you stay in control of the full dependency graph, not just the packages you reference directly.

Summary

Central Package Management is one of those features that makes you wonder how you managed without it once you adopt it. If you’re running a multi-project .NET solution, this is a straightforward improvement with immediate payoff — consistent package versions, cleaner project files, and a single place to make dependency updates.

Enjoy!

References

Development

Introduction to NuGet

NuGet is a package management system for Microsoft .NET and Visual Studio. It allows you to create simple and/or complex packages that install files into your projects, adds references and make any necessary configuration changes if needed. It also allows you to easily update to a newer version of the package if it’s available, or completely remove the package.

What is NuGet

“NuGet is a Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects that use the .NET Framework.

When you install the package, NuGet copies files to your solution and automatically makes whatever changes are needed, such as adding references and changing your app.config or web.config file. If you decide to remove the library, NuGet removes files and reverses whatever changes it made in your project so that no clutter is left.”

What is a NuGet Package

“Everything necessary to install a library or tool is bundled into a package (a .nupkg file). A package includes files to copy to your project and a manifest file that describes the contents of the package and what needs to be done to add or remove the library. Packages are bundled into feeds that Visual Studio accesses in order to present lists of available packages. There is an official feed that is the default source for NuGet, and you can contribute to that feed or create your own feeds.”

NuGet User Interface in Visual Studio

“NuGet runs in all versions of Visual Studio 2012, as well as Visual Studio 2010, Visual Web Developer 2010, and Windows Phone Developer Tools 7.1. You can find, install, remove, and update packages by using the Manage NuGet Packages dialog box or by using PowerShell command-line commands in the Package Manager Console dedicated Visual Studio window. Both options are accessible from the Visual Studio main menu; you can also open the dialog box from a Solution Explorer context menu.”

The Manage NuGet Packages Dialog Box

The following illustration shows the Manage NuGet Packages dialog box. You can access this by right clicking on your project in the Solution Explorer and then click on the Manage NuGet Packages… menu item.

sshot-409

The Manage NuGet Packages Console Window

The following illustration shows the Package Manager Console in Visual Studio. This console window lets you run NuGet PowerShell commands.

sshot-410

Supported Operating Systems

  • Windows 8
  • Windows 7
  • Windows Vista SP1
  • Windows Server 2008
  • Windows Server 2008 R2
  • Windows Server 2003 SP2
  • Windows XP SP3

Now that we have an idea of what NuGet is, let’s try it out.

Getting Started

To get started, you will need to download and install NuGet. Launch Visual Studio and then go to the Tools menu, then select the Extensions and Updates… menu item.

sshot-411

Then in the Online section, search for NuGet Package Manager or usually this is listed as one of the top items in the Visual Studio Gallery section.

Once NuGet Package Manager is selected, press the Download button. After a package has been downloaded and installed, you will see a green checkmark as illustrated below:

sshot-412

When the installation is complete, you will need to restart Visual Studio.

After Visual Studio is restarted, NuGet will then be ready for use.

NuGet is truly a pain-free way of installing and managing packages for your projects. NuGet takes care of everything and it just works!

Further Reading

  1. Managing NuGet Packages using the dialog. This describes in great detail how to find, install, update and remove packages from your project and/or solution.

    The solution option is neat as you simply select which projects you want to add the package to and then they’re all installed/updated at once.

  2. Creating and Publishing a Package.

References