MSBuild restore target - MSB4057: The target "restore" does not exist in the project

jcolebrand picture jcolebrand · Nov 15, 2017 · Viewed 12.5k times · Source

We have over 20 solutions in our main product portfolio (over 880 projects), and we have a complex set of build scripts that work well, but we are trying to automate the restore of nuget packages from within the msbuild pipeline. Currently this is done with a manual call out to nuget to restore the packages.

According to https://docs.microsoft.com/en-us/nuget/schema/msbuild-targets I should be able to run this command and have the restore run:

# works
& $script:msBuildPath $solutionName /t:build /v:q /clp:ErrorsOnly /nologo /p:...
# doesn't works
& $script:msBuildPath $solutionName /t:restore,build /v:q /clp:ErrorsOnly /nologo /p:...

However, when I add the restore, to the above it throws an error

MSB4057: The target "restore" does not exist in the project

Where do I start researching to understand why it can't find this target? We are predominantly on VS 2015 and .NET 4.6.2, so anything specific to VS2017 is not an option for me at this time.


If I omit the /v:q and /clp:ErrorsOnly flags I do get this (slightly sanitized solution/project names and paths)

PS Z:\git\company> build c
building Common\Common.sln
Build started 11/15/2017 11:08:54 AM.
     1>Project "Z:\git\company\Common\Common.sln" on node 1 (restore;build target(s)).
     1>ValidateSolutionConfiguration:
         Building solution configuration "DEBUG|Any CPU".
     1>Z:\git\company\Common\Common.sln.metaproj : error MSB4057: The target "restore" does not exist in the project. [Z:\git\company\Common\Common.sln]
     1>Done Building Project "Z:\git\company\Common\Common.sln" (restore;build target(s)) -- FAILED.

Build FAILED.

       "Z:\git\company\Common\Common.sln" (restore;build target) (1) ->
         Z:\git\company\Common\Common.sln.metaproj : error MSB4057: The target "restore" does not exist in the project. [Z:\git\company\Common\Common.sln]

    0 Warning(s)
    1 Error(s)

Time Elapsed 00:00:00.03
runBuildPackage :  ... failed
At Z:\git\company\psincludes\buildFunctions.ps1:11 char:5
+     runBuildPackage "Common\Common.sln"
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,runBuildPackage


msbuild failed
At Z:\git\company\psincludes\buildInternals.ps1:63 char:21
+                     throw "msbuild failed";
+                     ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (msbuild failed:String) [], RuntimeException
    + FullyQualifiedErrorId : msbuild failed

I realize some of this around is our internal tooling, I just didn't feel the need to obscure that part.

According to "the internet" this should just be "free" as part of the build process, and I'm not sure what we are missing in the csproj files here.

Answer

Martin Ullrich picture Martin Ullrich · Nov 15, 2017

The msbuild-integrated NuGet functionality is available in NuGet 4.0+ in conjunction with MSBuild 15, which means only in VS 2017. There is no support for the restore target for VS 2015.

The integrated restore in VS 2017 / NuGet 4 only works for projects using the new PackageReference style of referencing NuGet packages. It does not work for projects using packages.config. This new way of referencing packages is the default option for ASP.NET Core (both on .NET Framework / .NET Core), .NET Core and .NET Standard projects. It is opt-in for all other project types by selecting the style before the first install in the NuGet properties (Tools->Options->NuGet).

Note that calling /t:Restore,Build is not a good way to call this target, since restore may generate or change files that msbuild then doesn't reload. MSBuild 15.5 (upcoming update to VS 2017) introduces a /restore option instead that will call the restore target, then clear all caches which could not be cleared before and execute the normal build as requested. Before 15.5, it is best to make two distinct calls to msbuild.