In a previous post I talked about using variable for keeping NuGet packages across multiple projects; now there is a (potentially) better way.
In the previous post, it was demonstrated how to utilize “repository wide” variables located in a Directory.Build.props folder. With these variables defined, you could use the variable, rather than a literal value, in your csproj to keep dependencies throughout the repository on the same version.
There is now a feature (in review) at https://github.com/NuGet/Home/wiki/Centrally-managing-NuGet-package-versions which allows for doing the same thing, just in a more elegant way, at least in my opinion.
The in review feature relies on a new “repository wide” like file called “Directory.Packages.props”. Using https://github.com/Kritner-Blogs/DirectoryBuildProps/releases/tag/v1.1 as a starting point, we’ll introduce the centralized package versioning.
First, we’ll update the “Directory.Build.props” file to contain the following:
This tells visual studio, rider, the dotnet cli, etc., that the current folder, as well as its children (so repository wide if used at the root of the repo) that central package versioning is used.
Within the same folder as the “Directory.Build.props”, we’ll be creating a new file “Directory.Packages.props”. This file is used to specify the NuGet package version used for all packages used across the repository. Continuing to use the “Kritner.SolarProjection”, we’ll set up our new “Directory.Packages.props” file to specify the version.
<Project> <ItemGroup> <PackageVersion Include="Kritner.SolarProjection" Version="1.0.2" /> </ItemGroup> </Project>
In the above, we’re just defining the package as well as a version that should be used when that package is listed within any csproj file at the same level or as a child of the directory where the “Directory.Build.props” file is located.
Note that the above file does not include the package automatically in csproj files, it only defines the version to use when the package is listed in the csproj file.
Now that central package versioning is being used in our repository, we’ll need to make updates to our csproj file to make use of it; namely removing the version declaration from our csproj files.
Currently, we have the following in our csproj file:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Kritner.SolarProjection" Version="$(NuGet-Kritner-SolarProjection)" /> </ItemGroup> </Project>
In the above you’ll note that the old “variable style” version is being used, now with central package management, we don’t even need that:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Kritner.SolarProjection" /> </ItemGroup> </Project>
In the previous post we learned how to utilize variables to control our nuget package versions used across the repository, where desired. In this post we explored how to define a package version in one place, and for that same package version to be used across the whole repository.
There are a few other things to note when using central package versioning however:
- If a package version is defined in the csproj while central package versioning is turned on, you will be a compile error
- This is done (I believe) to help force the developer “into the pit of success”, making them aware of the fact that the package version is either already defined on a central level and you don’t need to specify the version, or that the package version needs to be defined in the “Directory.Packages.props” file.
- Related to the above point, you are still able to override the package version within a csproj by making use of the “OverrideVersion” property (as opposed to “Version” property) within the csproj file, as so:
- You can still make use of variables within your props files, as demonstrated in the above image. I like using these variables for defining a “package version” for a suite of packages, where they’re all released with a similar version number all at the same time, even one something didn’t necessarily change for each package in the suite. Examples of where this can be useful include the aspnetcore repository itself, as well as Microsoft Orleans - define the version of the package suite you want to use as a variable, then in your “Build.Packages.props” file, rely on that variable for each package used, rather than defining the literal package version for each package.