I have a .NET app called Application
.
This application depends on two NuGet packages:
Database
, version 2.*Logging
, version 3.*
The Database
package depends on two additional packages:
DTO
, version 1.*DAL
, version 4.*
Currently, Application
uses these concrete package versions: Database
version 2.1, Logging
version 3.1.
I build my Application
, NuGet resolves and downloads the dependencies, so I get DTO
version 1.5 and DAL
version 4.0. I put my Application
into an installation package and deliver to my customer. I tag this release in git with app-1.0
.
So my customer gets the following binaries:
Application.exe
, version 1.0Database.dll
, version 2.1Logging.dll
, version 3.1DTO.dll
, version 1.5DAL.dll
, version 4.0
One year later, the customer files a bug which I need to thoroughly analyse. To reproduce the issue, I need the same binaries as the customer, so I check out the tag app-1.0
and want to build my application.
Meanwhile, the DAL
and the DTO
packages were updated on the NuGet feed: latest DTO
version is 1.7 and DAL
version is 4.5.
My questions are:
- When I build my application now, does NuGet resolve the
Database
dependencies to the latest available versions? So do I getDTO 1.7
andDAL 4.5
instead ofDTO 1.5
andDAL 4.0
(which were used to buildapp-1.0
)? - If yes, how can I ensure the binary reproducibility of my release using NuGet?
- If no, how does NuGet manage to resolve the "right" references?
NuGet introduced lock files in version 4.9 (Visual Studio 2017, 15.9), .NET Core SDK 2.1.500. The blog post that introduces it is even titled "Enable repeatable package restores using a lock file"
The blog post only lists one way to enable lock files. One way is to create an empty file named
packages.lock.json
in the same directory as your project file (csproj
), then do a restore. Another way is to rundotnet restore --use-lock-file
on the command line. Another way is to set theRestorePackagesWithLockFile
MSBuild property totrue
, which is possible in many ways (property in your project file, property inDirectory.Build.props
, environment variable, command line argument).Once the lock file is created, it will always be used, so you no longer need to explicitly opt-in as you need to the first time. Note that restore will update the lock file by default when it finds changes. If you want to fail restore when it can't restore the exact same packages, you need to opt-in to "locked mode", for example
dotnet restore --locked-mode
, which you probably want to do on your CI machines.