Central Package Management (CPM) in .NET Core

Introduction

A fundamental component of NuGet is dependency management. It might be simple to manage dependencies for a single project. As multi-project solutions begin to grow in size and complexity, managing dependencies can become challenging.

You can take advantage of NuGet's central package management (CPM) features to handle shared dependencies for numerous projects all from one convenient location.

NuGet package dependencies

NuGet package dependencies have been managed on below ways.

  • packages.config: An XML file that previous project types used to keep track of the packages the project referenced.
  • <PackageReference />: NuGet package dependencies are defined by an XML element that is utilized in MSBuild projects.

Enabling Central Package Management

You must create a Directory.Packages.props file at the root of your repository and set the MSBuild value ManagePackageVersionsCentrally to true in order to begin using central package management.

Then, using <PackageVersion /> elements that identify the package ID and version, you declare each of the corresponding package versions needed for your projects inside.

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="{{package name}}" Version="{{version number}}" />
  </ItemGroup>
</Project>

For each of the projects, we need to define package references, and each of the projects belongs to the same version.

<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net6.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
	</PropertyGroup>
	<ItemGroup>
		<PackageReference Include="{{package name}}" />
	</ItemGroup>
</Project>

You're controlling your versions centrally and utilizing central package management now!

Let’s check with the demo.

Create one application for whatever you want for the project. Here I have created the console application for demo purposes.

CPM Demo

In the above image, CPMDemo is the console application, and CPMDemo.Utility is the class library project.

We can create Directory.Packages.props is the root-level file in our console application.

Here is the content of the directory package file.

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="Newtonsoft.Json" Version="13.0.1" />
    <PackageVersion Include="Microsoft.EntityFrameworkCore" Version="6.0.27" />
  </ItemGroup>
</Project>

Here is the content of the CPMDemo.csproj changes.

<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net6.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
	</PropertyGroup>
	<ItemGroup>
		<PackageReference Include="Newtonsoft.Json" />
		<PackageReference Include="Microsoft.EntityFrameworkCore" />
	</ItemGroup>
</Project>

Here is the content of the CPMDemo.Utility.csproj changes.

<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<TargetFramework>net6.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
	</PropertyGroup>
	<ItemGroup>
		<PackageReference Include="Newtonsoft.Json" />
		<PackageReference Include="Microsoft.EntityFrameworkCore" />
	</ItemGroup>
</Project>

Once you have completed the above changes on your application side, you just need to build the solution, and then after expanding the dependencies and expanding the packages as well, you will see the packages have been added to your application with the mentioned package versions.

Below is a screenshot taken before building the solution, so at that time we hadn’t added any packages to our application.

CPMDemo.Utility

Below is a screenshot after building the solution and being able to see the added packages in our application.

Packages

Central Package Management rules

There are several restrictions governing the location of the Directory.Packages.props file within a repository's directory as well as its context. For the sake of simplicity, each project is evaluated using a single Directory.Packages.props file.

This indicates that the file nearest to the directory of your project will be considered for it if you have several Directory.Packages.props files in your repository. This gives you additional authority over your repository at different levels.

Repository structure

As an illustration, look at the repository structure below:

Repository structure

Here is the explanation for better understanding.

  • ProjectName1 will assess the Directory.Packages.props file in the Repository Name\Solution1\ directory.
  • ProjectName2 will assess the Directory.Packages.props file in the Repository Name\ directory.

In this manner, we can concentrate the packages that we need on the application side. It will also be simple to maintain—we just need to change one location, and it will reflect everywhere.

Happy learning!!