NuGet packages often have dependencies on other NuGet packages. These dependencies are specified in the <dependencies> element of the package’s NuSpec file. When installing a package with dependencies, NuGet will ensure that all the dependencies for that package are downloaded and installed first before installing that package. The following document describes the rules NuGet uses when choosing which dependencies to install.

Dependency Resolution Rules

A dependency consists of an id which identifies a package as well as a version range specification which describes the version or range of versions for the dependency. For example, the following example is a dependency on versions 1.2.3 – 3.0.0 (exclusive) of a package named “subkismet”

<dependency id="subkismet" version="[1.2.3, 3.0.0)" />

Determining which version of the package to install in order to fulfill this dependency is a multi-phase process.

If the dependency is already installed, then one of two things happens:

  1. If the installed dependency is within the version range, then nothing more needs to happen. The dependency is met.
  2. If the installed dependency is outside of the version range, installation fails. (Version leveling in a future version of NuGet will fix this.)

If the dependency is not installed, NuGet goes through the following steps:

  1. NuGet enumerates every version of Subkismet within the feed that’s within the version specification.
  2. NuGet then narrows that set to just the packages with the lowest Major/Minor version.
  3. Of the remaining packages, NuGet picks the one with the highest version number.

Let’s look at a more concrete example of this algorithm in practice. Given the above dependency, suppose the Package Source contains the following versions of Subkismet and Subkismet is not installed in the project:

  • Within the feed: 0.5, 1.2.2, 1.2.3.8, 1.2.5, 1.3.0, 2.5.0, 3.0.0

The steps to determine which version to install are:

  1. The versions of the package in the package source that are within range are: 1.2.3.8, 1.2.5, 1.3.0, 2.5.0
  2. Within those, the packages that have the lowest major/minor version are: 1.2.3.8, 1.2.5
  3. We pick the highest version of the remaining packages: 1.2.5

If no packages exist in the feed meeting the version range requirement, the dependency cannot be met and the package installation will fail.

Package Dependency Leveling Scenarios (POST 1.0)

In the previous section, we looked at how dependencies are chosen when the dependency is not yet installed. If a dependency is already installed, but is outside the version range, installation could fail. The following section describes how NuGet can resolve such scenarios.

Dependency Upgrade Scenario:

Installed

  • Subkismet –> log4net [1.0.0, 3.5.0)
  • Log4Net 1.0.0

Installing: Elmah –> log4net [2.0.0, 4.0.0)

Available: log4net v1.0, 1.1, 2.0.0, 2.0.5, 2.1.0, 3.0, 3.2.0, 3.6.0, 4.0.0

Result: Log4Net upgraded to v2.0.5

In this scenario, Log4Net 1.0 is already installed, but we’re trying to install a package (ELMAH) which depends on a versions 2.0.0 – 4.0.0 of Log4Net. The existing installed log4net doesn’t meet the dependency requirements of the package we’re trying to install.

NuGet should upgrade the Log4Net dependency to a version that fits within the intersection of both ranges. The logic should be:

  1. List every version of the dependency (log4net) that’s available from the package source and fits within the intersection of the version ranges for all packages that depend on log4net. In this case that’s 2.0.0, 2.0.5, 2.1.0, 3.0.0, 3.2.0
  2. As before, then narrow that set to the ones with the lowest Major/Minor version: 2.0.0, 2.0.5
  3. Choose the highest remaining version number: 2.0.5

Dependency Downgrade Scenario:

Installed

  • RouteDebugger –> WebActivator [2.0, 3.5)
  • WebActivator 2.5

Installing: Ninject –> WebActivator [1.0, 2.1)

Available: WebActivator v1.0, 1.1, 2.0, 2.1, 2.5, 3.0, 3.2, 3.6, 4.0

Result: WebActivator downgraded to v2.0

In this scenario, WebActivator 2.5 is already installed, but we’re trying to install a package (Ninject) which depends on a lower version of Log4Net. NuGet should downgrade the Log4Net dependency to a version that fits within the intersection of both ranges. The logic is the same as in the dependency upgrade scenario.

Conflict Resolution

Installed

  • Spark –> Autofac [2.0.0, 2.5.0)
  • Autofac 2.2

Installing: IdenticonHandler –> AutoFac [3.0.0, 4.0.0)

Available: AutoFac v2.1.0, 2.2.0, 3.0.0, 3.2.0, 3.6.0, 4.0.0

Result: Conflict!

In this situation, no version of AutoFac will satisfy all dependencies. At this point, the user needs to make a choice. The prompt should be something like:

I've detected that you want to install IdenticonHandler v1.0 which has a dependency on AutoFac v3.0 - 4.0. You already have AutoFac v2.2 installed as a dependency of Spark v1.0. There is no AutoFac package that will satisfy the dependencies of IdenticonHandler and Spark. Would you like to:
  (1) Continue without dependencies?
  (2) Continue and upgrade dependencies (aka upgrade IdenticonHandler to 3.6) anyways (and possibly render existing packages useless)? DO NOT choose this unless you know what you are doing.
  (3) Cancel and do not add IdenticonHandler to your packages?

Installing Package Leveling

This scenario allows the user to choose a different version of the package they’re attempting to install which will meet dependency requirements.

Installed

  • T4MVC –> SQLCE [1.0.0, 2.0.0)
  • SQLCE 1.5

Installing: NHibernate 4.0 –> SQLCE [3.0.0, 4.0.0)

Available: SQLCE v1.1, 1.5, 2.5, 3.0, 3.2, 3.5, 4.0, NHibernate 2.0 –> SQLCE [1.5,2.0)

Result: Package Leveling prompt.

In this scenario, the user is attempting to install NHibernate 4.0 which depends on SQLCE 3.0 – 4.0. But the user already has SQLCE 1.5 installed and that dependency cannot be upgraded because another package, T4MVC, depends on that version of SQLCE.

But it just so happens that there’s another version of NHibernate in the feed that would be compatible with the packages that are currently installed, NHibernate 2.0. With the package leveling feature, we could prompt the user with the conflict and let the user choose a lower version of the current package.

I've detected that you want to install NHibernate v4.0 which has a dependency on SQLCE v1 - 2. You already have SQLCE v1.5 as a dependency of T4MVC v1.1. However, there is a version of NHibernate (v2.0) that has a dependency that would not conflict with T4MVC. Would you like to:
  (1) Continue without dependencies?
  (2) Continue and upgrade dependencies (aka upgrade SQCLE to 3.0) anyways (and possibly render existing packages useless)? DO NOT choose this unless you know what you are doing.
  (3) Install NHibernate to v2.0 instead and continue?
  (4) Cancel and do not add NHibernate to your packages?

Installed Package Leveling

This scenario is a slight variant of the previous scenario allows the user to choose to upgrade an already installed package in order to avoid dependency version conflicts.

Installed

  • T4MVC 1.1 –> SQLCE [1.0, 2.0)
  • SQLCE 1.5

Installing: NHibernate 4.0 –> SQLCE [3.0.0, 4.0.0)

Available: SQLCE v1.1, 1.5, 2.5, 3.0, 3.2, 3.5, 4.0, T4MVC 2.0 –> SQLCE [1.5,4.0)

Result: Package Leveling prompt.

In this scenario, the user is attempting to install NHibernate 4.0 which depends on SQLCE 3.0 – 4.0. But the user already has SQLCE 1.5 installed (as a dependency of T4MVC 1.1) and that dependency cannot be upgraded.

But it just so happens that there’s a newer version of T4MVC in the feed that would be compatible with the package that the user is attempting to install (NHibernate 2.0). With the package leveling feature, we could prompt the user with the conflict and let the user choose to upgrade the installed version of T4MVC.

I've detected that you want to install NHibernate v4.0 which has a dependency on SQLCE v1 - 2. You already have SQLCE v1.5 as a dependency of T4MVC v1.1. However, there is a version of T4MVC (v2.0) available in the feed that has a dependency that would not conflict with NHibernate 4.0. Would you like to:
  (1) Continue without dependencies?
  (2) Continue and upgrade dependencies (aka upgrade SQCLE to 3.0) anyways (and possibly render existing packages useless)? DO NOT choose this unless you know what you are doing.
  (3) Upgrade T4MVC to v2.0 and continue?
  (4) Cancel and do not add NHibernate to your packages?

Last edited Dec 16, 2010 at 11:56 PM by haacked, version 10