NuGet Tip #3: Manage packages at the solution level
Now that you’ve enabled package restore> on build and set up your own package feed it’s time to take a closer look at how we add packages to our projects.
Most .NET developers spend a lot of time in visual studio and are more naturally comfortable with the GUI tooling than with command-line alternatives. The most common way that I see developers adding a NuGet dependency to a project is to right-click on the references node in the solution explorer and select “Manage NuGet Packages…”
They pick their package, it downloads, the proper references are added to the project, and off they go.
Truthfully, this is all you need to get started and is enough for demos and screencasts, but let’s think about what is happening under the covers.
Under the covers
Once you select a package in the “Manage NuGet Packages” wizard and click install, here is roughly what happens:
- Visual Studio reaches out through NuGet to download the latest version of the package bits into your packages folder.
- If your project does not have a packages.config file, an empty one is added to your project.
- If your packages.config file has an existing reference to an older version of the new package, the old one is removed, including the references into the old package folder.
- A
<Package />
node describing the package is inserted into the project’s packages.config file - A reference into that package folder is added to the project.
There are two things about this process that may get you into trouble over time or on a large project:
- by default, nuget installs the latest version available at the time the reference is added.
- when nuget adds a package, it adds two independent references, one in the package.config file and one as a reference in the project file.
What’s wrong with the latest version?
On a large project, you often wind up adding new projects over time, often weeks or months apart. If you are always installing packages one project at a time, and a package author happens to release an update in between your two installs, you may wind up with two projects in your solution referencing different versions of a package.
In the best case, the updated package is fully backwards compatible with the old one and the difference may be transparent, or easily fixable with binding redirects. In the worst case, however, an upgraded package by contain breaking changes or expose a completely different API. Additionally, I have noticed that ClickOnce installs will fail if they contain two instance of the same assembly that are stamped with different version information.
When using nuget on the command line or in the powershell console inside visual studio you have options for specifying a specific version of a package, but no such luck in the Manage NuGet Packages
dialog.
So how to encourage our GUI-bound brothers and sisters to use consistent package versions across a project? Train them to manage packages at the solution level, as I explain below.
Where is my package reference?
Another quirk of the Manage Package References
dialog is that its Installed Packages
list appears to populate from the package.config file, ignoring completely any references that you have in your project. If for some reason you edit your packages.config file and remove a <package/>
node, the visual studio tooling will no longer include that package under the installed list in the Manage Package References
dialog nor will it restore that package on build, even if the reference in the project file remains pointed into the package folder.
Manage packages at the solution level
A good rule of thumb that addresses both of these issues is to always manage packages at the solution level. Right-click on the Solution node in the Solution Explorer and select Manage NuGet packages for Solution
.
The solution-level Manage NuGet Packages
dialog is nearly identical to the project-level Manage NuGet Packages
dialog, but instead of Install
buttons you get Manage
buttons and a list in the bottom part of the right-hand column of which projects have that package installed.
Clicking on the Manage
button will open a Select Projects
dialog with a list of projects in your solution and checkboxes beside each one.
Check off the projects into which you want to install the new package, or check off new projects that you want to add this package to, click OK, and Visual Studio will loop through the projects uninstalling or installing the package based on the checkmark.
Were are my installed packages?
Similar to the project-level package dialog, this solution-level one has a quirk of its own. Rather than reading the packages.config files of each project in your solution, the “Installed” tab appears to populate based on scanning the packages folder of your project source files.
This means that if you have enabled package restore and not checked any projects into source control, a running this dialog after a fresh checkout will show you that no packages are installed.
As well, if you have been working with a solution over time and upgraded a package once or twice along the way, each version of that package that is living in the packages folder of your source files will appear in the “Installed” list of the solution-level packages dialog.