Migrate away from MSBuild-based NuGet package restore

4 minute read

Back in the days...

NuGet package restore used to be MSBuild-based. You had to explicitly enable it using the context menu on a Visual Studio solution: right-click the solution and select Enable NuGet Package Restore. In fact, if you go to the NuGet docs, you'll see that this scenario is still fully documented. A quick search for "package restore" will throw this old scenario "in your face", as it is the first hit in the search results.

First hit in search results when looking for Package Restore on the NuGet docs

To be fair, the page does highlight that there's a new way of doing this. But many people don't read. At best some look at the pictures. That's why I won't even include a screenshot of that page, as it is full of project setup details that no one should ever go through again. Instead, I'll give you a clear picture of what you should not do :)

Don't do this!

You're doing it wrong!

I can't stress it enough. I'm a huge proponent of NuGet package restore! But if you follow this workflow, then please do it right! (and design for failure, obviously).

The MSBuild-based NuGet package restore has issues. For one: it's MSBuild-based. This means that anything that happens during package restore is run within the MSBuild process, which is particularly annoying for packages that want to modify project files and inject MSBuild targets (as these aren't picked up until the next run).

The moment you manually enable NuGet package restore through the context menu, you're actually installing a few NuGet packages: NuGet.Build, which depends on NuGet.Commandline. The nuget.exe along with a nuget.config and a nuget.targets file are created within a .nuget folder, and all projects that have NuGet package references will be modified to import the NuGet.targets file. The nuget.targets file ensures that nuget.exe is invoked during builds (as in: not before builds!).

The right way

All you need to do is to make sure that your Visual Studio options allow NuGet to download any missing packages in a pre-build phase (note: even before MSBuild compilation starts!). I'm not going to rephrase step-by-step what you should do as David Ebbo already has a great post explaining all of this!

Ensure NuGet is allowed to download missing packages

If you're cloning a new project that did not commit any NuGet packages (and is not using the old MSBuild-based restore), then it just works!

Migrating from the old way

If you still have a .nuget folder in your repository, then please migrate away from it! Think about all those adorable kittens...

Did you know this has been documented on the NuGet Docs all along?! Follow this how-to and save yourself and everyone using your codebase some trouble and follow it step-by-step.

Even better: automate your migration using these awesome scripts!

For those not using Visual Studio or perhaps not even on the Windows platform: a simple call to nuget.exe restore *.sln before calling the compiler does the trick as well (add it to your build script, or perhaps you can configure your IDE to do this for you before each build...).

But... my precious (build server)

As long as you did not set the environment variable EnableNuGetPackageRestore=false then you're good to go. (default: EnableNuGetPackageRestore=true)

The following tools support the new automatic package restore out-of-the-box and Just Work™!

The next list of tools requires some minor modifications to the build process:

  • Visual Studio Online / Team Foundation Server (how-to)
  • TeamCity (how-to)

Note that you don't need to worry about development machines! As long as you all have the latest NuGet Visual Studio extension installed (as of NuGet v2.7).

Upgrading your NuGet extension is generally a good idea anyway, as there are lots of improvements in the latest versions!

Going forward

Here's what I'd love to see happen going forward:

  • The NuGet Docs should by default show the new non-MSBuild-based package restore instructions. There are close to none, but this should be thrown in your face when looking for it.
  • Migration instructions should be clearly linked to.
  • The old MSBuild-based instructions should be archived, perhaps even removed.
  • Currently, when installing a NuGet package that injects MSBuild targets, you'll see the following piece of logic appear in your project files:
      <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
        <PropertyGroup>
          <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
        </PropertyGroup>
        <Error Condition="!Exists('..\packages\SomePackageId\Build\SomeMSBuild.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\SomePackageId\Build\SomeMSBuild.targets'))" />
      </Target>
    
    This is horrible as it is suggesting you to do the wrong thing: you should call nuget.exe restore instead!
  • The context menu-item to manually enable NuGet package restore (MSBuild-based) should be completely removed from the extension. I don't see any reason to keep it. Do you? If you do, please comment on this CodePlex issue, if you agree, then vote for it :)
  • Preferably, the next NuGet Visual Studio extension detects you are using the "old" restore option when you open a solution, and asks you to migrate/upgrade to the new way. Ideally, this removes the targets and import statements, and custom package sources and credentials are taken into account if they are in the nuget.config file. </ul> </p>

    I'm happy to take on an issue or send PR's for any of the above, but some of the bullet-points seem too big to me to be taken in as a PR.

Leave a Comment