Home > Software design >  Which version of .NET class will be used?
Which version of .NET class will be used?

Time:05-14

I have a team using .Net Core 5.0 for their application. They're pulling in some packages from Nuget that are earlier versions of some .Net Core packages that that are explicit dependencies of other packages they're using. For example, they're pulling in System.Net.Http 4.3.4 (https://www.nuget.org/packages/System.Net.Http/). This same class is included in .Net Core 5.0.

My question is: at runtime which version of System.Net.Http will be used, 4.3.4 in the separate DLL included with the app or 5.0.x included in the main .Net Core library?

CodePudding user response:

There's two parts here:

  • When multiple package versions are listed as a dependency, which one is picked/used?

  • When a package is part of the .NET runtime itself, is it preferred over the package from nuget.org?

There's an answer to the first question in the dotnet docs:

At build time, NuGet analyzes all the packages that a project depends on, including the dependencies of dependencies. When multiple versions of a package are detected, rules are evaluated to pick one. Unifying packages is necessary because running side-by-side versions of an assembly in the same application is problematic in .NET.

In other words, only package is picked and used. The rules are described here. The relevant one is:

When the package graph for an application contains different versions of the same package, NuGet chooses the package that's closest to the application in the graph and ignores all others. This behavior allows an application to override any particular package version in the dependency graph.

In the example below, the application depends directly on Package B with a version constraint of >=2.0. The application also depends on Package A which in turn also depends on Package B, but with a >=1.0 constraint. Because the dependency on Package B 2.0 is nearer to the application in the graph, that version is used

If you build with detailed logging, you should see the the rules being applied as well as the final version that's picked.

For the second question - what happens when a class is part of .NET (Microsot calls this "inbox") and also available on nuget.org - is a bit trickier.

There's a github issue here where several .NET developers try and answer this question in some detail. Here's the relevant bits:

In 2.1 and above the runtime resolution is based on assembly version and file version. If the app has the same assembly as the shared framework the assembly version will be compared (based on records in .deps.json), the higher will be used. If equal, the file version is compared (again based on records in .deps.json), the higher will be used. If both versions are equal, then the file from lower level framework will be used.

So the assembly from the app is only used if it has higher version than the one in framework. On equality the framework assembly is used (we assume that if both versions are the same, then the files are basically identical).

There's also this interesting quote:

General advice is to stop using the System.Net.Http package. At best it redirects to the inbox version, at worst it causes weird conflicts.

  • Related