Single package version per solution

Issue 913

Problem Statement

When using an assembly, it’s rare for developers to want different versions of the same assembly within a single solution. Most of the time, if you’re using an assembly in one project of the solution, and need to use the same assembly in another project in the same solution, you want the exact same version. And if you update the assembly in one project, you’re going to want to update the assembly in the other.

This conclusion is based on the results of a recent poll we conducted.

However, you can easily get into this state with NuGet where different projects in the same solution have different versions of a common package.

Feature  Proposal

The proposal is to change NuGet to guarantee that all projects in a solution use the same version of any given package

Let’s look at multiple ways this can happen and the proposed new behavior to handle this.

For all these examples, we’ll use the following Solution as our example. It contains two projects, MvcApplication1 and ClassLibrary1.

MvcApplication1 - Microsoft Visual Studio (Administrator)

Installing Packages

  • Install Log4Net 1.0 into MvcApplication1
  • Install Log4Net 1.1 into ClassLibrary1

Simply installing packages can get you into a bad state. Suppose you install Log4Net 1.0 into MvcApplication1. Then a few days later Log4Net 1.1 comes out and you install it into ClassLibrary1. Now you have two projects with different versions of the same assembly.

Fix: In this situation, NuGet will upgrade Log4Net in all projects (MvcApplication1) to the same version being installed.

Updating Packages

  • Install Log4Net 1.0 into MvcApplication1
  • Install Log4Net 1.0 into ClassLibrary1
  • Update Log4Net to version 1.1 in ClassLibrary1

This is really just a variant of the previous case. After installing the same library to both projects, we go and update one of the packages to the latest version.

Fix: In this situation, NuGet will upgrade Log4Net in all projects (MvcApplication1) to the same version.

Installing/Upgrading Dependencies

In this case, MyLogger 1.0 is a package that depends on Log4Net 1.1.

  • Install Log4Net 1.0 into MvcApplication1
  • Install MyLogger 1.0 into ClassLibrary1

Notes: Again, this is really a variant of the first case, but is worth calling out because it’s more subtle. In this case, installing MyLogger 1.0 will bring in a newer version of Log4Net into the project. In this case NuGet will need to upgrade Log4Net to this version in all projects.

Interesting cases

Installing a lower version

  • Install Log4Net 1.1 into MvcApplication1
  • Install Log4Net 1.0 into ClassLibrary1

in this case, the developer is attempting to install an older version of a library into a class library for whatever reason. This couldn’t happen via the dialog, but could happen in the console. The later examples will show why this might happen.

Open Question:

  • What should NuGet do in this situation?
    • Downgrade Log4Net in all other projects to the target version?
    • Install the later version of NuGet?
    • Throw an error stating a newer NuGet is already installed in the solution.

Answer: Throw an error.

Installing a lower version due to dependencies

In this case, MyLogger 1.0 is a package that depends on Log4Net >= 1.0.

  • Install Log4Net 1.1 into MvcApplication1
  • Install MyLogger 1.0 into ClassLibrary1

In his case, since the existing Log4Net version in the solution is compatible with the version range of the package we’re installing, NuGet will instead install Log4Net 1.1 into ClassLibrary1 rather than Log4Net.

Conflicts

One result of this feature is there are more chances for version conflicts because installing/upgrading packages will check all projects in a solution for a conflict. Note that all other conflict cases are pretty much similar to the ones we already have today. The only change is looking at every project for conflicts.

Installing a conflicting package

In this case, MyLogger 1.0 is a package that depends on Log4Net == 1.0 (exactly 1.0).

  • Install MyLogger 1.0 into MvcApplication1 (and thus Log4Net 1.0)
  • Attempt to install Log4Net 1.1 into ClassLibrary1

In this scenario, attempting to install Log4Net 1.1 into the second project will attempt to upgrade Log4Net to 1.1 in the first project. Unfortunately, this will cause a conflict with the MyLogger dependency on Log4Net.

NuGet will fail the installation and report a conflict with the package in the first project. Note this is the same behavior as before, but now NuGet looks at all projects for conflict.

Last edited Apr 29, 2011 at 5:24 PM by haacked, version 9

Comments

mfreidge Jul 31, 2012 at 10:01 PM 
Fixed as http://nuget.codeplex.com/workitem/431

kelps May 3, 2011 at 7:12 PM 
Does anything change in the packages folder in the solution? If there won't be different versions inside a solution anymore, does it make sense to keep the NuGet package version in the folder name?

I find that this adds some unecessary noise in my source code tree. Instead of new folders/package version I would prefer to have a single folder/package inside the packages folder. No need for the version number to be there.

If I update to a new package, do all the checks and if ok, clear the folder and update it with the content of the new package.

If this could be configurable, even better. This way, projects that rely on the current workflow won't break. Maybe a simple true/false attribute in the repositories.config would suffice. This would set the new default for new solutions using NuGet but keep the current workflow for current projects.

This is based on my personal preference and experience with external references, but I know a lot of other developers that share the same preference. I've been working with a similar workflow for over 5 year now, only my packages folder is called "_References" and I had to update the packages manualy (the _ is there just to differentiate the folder and make it the first in the list in Windows Explorer)