Today I Learned How to Lock a Dependency to a Specific Version in Project JSON

While upgrading the NUnitXmarin project the project maintainers asked me lock the version of NUnit to a specific version.  They where also kind enough to provided a link to a possible solution.  Lets test if it works.

First lets review how NuGet resolves dependencies.  If you specify a dependency version the standard way, i.e. just listing the version number with not brackets, NuGet tries to find the version you specified of the next highest version.

For example the NuGet feed for NUnit has the following versions in it’s feed:

3.6.1
3.7.0
3.7.1
3.8.0
3.8.1

If you list version 3.7.1 in project.json file, as shown below, then NuGet uses version 3.7.1.  Duh.

"dependencies": {
  "NUnit": "3.7.1"
}

Now say you list version 3.7.99 as shown below.  Now 3.7.99 does not exist so NuGet find the next highest version, which is 3.8.0, and uses that version.

"dependencies": {
 "NUnit": "3.7.99"
}

When you compile you will see a message similar to the below.

Dependency specified was NUnit (>= 3.7.99) but ended up with NUnit 3.8.0.

NuGet Dependency Resolution Message

To tell NuGet to only use the version you specified you need to put square brackets around the version number.  This changes the logic from “>= Version#” to “= Version#”.

"dependencies": {
 "NUnit": "[3.7.99]" 
} 

Now when you try to build you will get an error because version 3.7.99 does not exist and NuGet will not try to find a newer version.

NuGet Package restore failed for project Runner\nunit.runner.Droid for 'NUnit (= 3.7.99)'.

NuGet Dependency Error Message

That’s great you say, but why would you link to a version that does not exist?  That is stupid.

Let’s try something that might actually happen.  Your project references a project but another package links to a different version.  Say you have the following in your JSON file:

"dependencies": {
  "NUnit": "[3.6.1]",
  "NUnitLite": "3.8.1" 
} 

NUnitLite 3.8.1 references to NUnit 3.8.1.  If you compile you get the following warning:

Detected package downgrade: NUnit from 3.8.1 to 3.6.1  
ClassLibrary1 (>= 1.0.0) -> NUnitLite (>= 3.8.1) -> NUnit (= 3.8.1)  
ClassLibrary1 (>= 1.0.0) -> NUnit (= 3.6.1)

NuGet Dependency Warning Message

That’s good.  It’s what we wanted.  Now what happens if we remove the square brackets from the NUnit dependency so our JSON file looks like:

"dependencies": {
 "NUnit": "3.6.1",
 "NUnitLite": "3.8.1" 
} 

Will it use NUnit 3.6.1 that we reference in the project or NUnit 3.8.1 referenced by NUnitLite?

Detected package downgrade: NUnit from 3.8.1 to 3.6.1  
ClassLibrary1 (>= 1.0.0) -> NUnitLite (>= 3.8.1) -> NUnit (= 3.8.1)  
ClassLibrary1 (>= 1.0.0) -> NUnit (= 3.6.1)

NuGet Dependency Warning Message

Wait, that is exactly the same message we got last time.  What is going on?  It turns NuGet prefers the version of a package directly referenced by your project then one referenced by another package.  This is all explained in the How NuGet resolves package dependencies article but in summary NuGet tries to use the lowest version it can get away with with direct references overriding sub-references.

P.S. – I’m glad Barenaked Ladies (it’s a Canadian band, link is SFW) where able to continue without Steven Page but I miss his melancholy.  Plus him and Ed harmonized really well together.  This is one of my favorite melancholy BNL songs.  Yes I like it more then Brian Wilson.  Just ignore the cheesy video.

I couldn’t tell you
That I was wrong
I chickened out grabbed a pen and a paper
Sat down and I wrote this song

I couldn’t tell you
That you were right
So instead I looked in the mirror
Watched TV, laid awake all night

This entry was posted in Uncategorized. Bookmark the permalink.