Dependency Resolution

When building an ASP.NET 5 application your application will depend on many packages - more so than in MVC 5, as the entire stack is divided into a new set of packages. When loading an application the runtime will walk the dependency tree and load all the required dependencies. Part of this process is deciding which of the packages will be loaded when there are multiple versions of the same package in the dependency tree. This happens in almost all trees, especially when your application uses packages from the Cloud Optimized subset of the CLR because most packages will end up depending on common packages such as System.Collections.

Dependency Loading Rules

There are two main scenarios that the dependency reasons about: nearest-wins and cousin dependencies.

Nearest wins means that the dependency resolver prefers versions that are "closer" to the application, but only if they are an ancestor of the dependency being rejected.

[[/images/nearestWinsApp.png|alt=Application using nearest wins]]

FIGURE 1 APPLICATION USING NEAREST WINS

In Figure 1, the green packages (A 1.0 and B 2.0) would be loaded, while the orange package (B 1.0) would be ignored. This is because a direct parent of "B 1.0" depends on a different version of B, and the resolver prefers that version.

Nearest-Wins allows a package/application to override any particular version of a package in its dependency tree by directly depending on the version it wants.

[[/images/nearestWinsPackage.png|alt=Package using nearest wins]]

FIGURE 2 PACKAGE USING NEAREST WINS

In Figure 2 package A is stating that it depends on Package C 2.0 even though B depends on Package C 1.0. Because A is taking a direct dependency on C, and is an ancestor of C, the nearest wins rule applies and the resolver will use C 2.0. [[/images/cousinDependencies.png|alt=Cousin dependencies]]

FIGURE 3 COUSIN DEPENDENCIES

In Figure 3 both Package A and C depend on Package B. But C is not an ancestor of "B 1.0" so the nearest wins rule does not apply. Instead the resolver uses the minimum acceptable version, which in this case is "B 2.0".

When deciding between multiple cousin dependencies, the resolver use the lowest version that satisfies all version requirements.

Today, because the resolver treats versions as minimums, that generally means the highest version wins. However, if version ranges are introduced in the future the algorithm will need to choose the best version that fits within the range constraints. This could mean that the highest version is not chosen or that the runtime throws an exception due to irreconcilable range differences.

In Figure 4, below, we can see the dependency tree of an actual application. In this example the red nodes are dependencies that are eclipsed by dependencies of their ancestors. Eclipsed nodes could have the same version as the thing that eclipsed them. [[/images/actualApplicationsDependencies.png|alt=Application dependencies]]

FIGURE 4 ACTUAL APPLICATION

This example is the same scenario as the first example that was described: the application is taking an explicit dependency on Microsoft.Bcl.Immutable 1.1.20-beta, which is taking precedence over version 1.1.18-beta that the EntityFramework package is using.