Vs2017: NuGet packages not restored with MSBuild

2020-07-14 09:48发布

问题:

  1. I build from VS2017 and the packages are downloaded and the projects build.
  2. Then I nuke the packages folder.
  3. Then I build using MSBuild the projects fail because the packages don't exist, they haven't been restored.

I have "download missing packages" on

The project files would have been originally created in VS 2013

The build.proj using the MSBuild task to build the solution.

<MSBuild Projects ="$(root)\src\MySolution.sln" ContinueOnError ="false" Properties="Configuration=$(Configuration)">
    <Output ItemName="OutputFiles" TaskParameter="TargetOutputs"/>
</MSBuild>

My google-fu has failed me, any and all ideas will be greatfully received.

回答1:

packages.config based projects need to be restored via NuGet, not MSBuild. Visual Studio does this when requesting a build via VS. If you need to do it from command line, you need to use the command line nuget.exe utility to restore the packages.

Only the PackageReference way of referencing NuGet packages is integrated into MSBuild. You can switch to this format by uninstalling all NuGet packages from the project, and changing the default package management format or select the "Allow format selection on first package install" checkbox. Then you can re-add the packages (only top-level packages are needed) and make sure it does not generate a packages.config file.

There's a few issues here:

  1. After a restore, MSBuild has to re-evaluate the project file. When using the <MSBuild> task inside a CI script, this only happens when a different set of properties are passed to the task. This is because the Restore generates auto-imported files in the obj\ directory that are checked for during the evaluation.

  2. Should the restore not generate, but alter these files, this is not enough and the project has to be re-evaluated with clean xml caches. This is not possible with the <MSBuild> task. MSBuild 15.5 has introduces a /restore option to execute a Restore target, then clean these caches (for which there was no API before) and execute the rest of the build as requested. Before 15.5, two separate invocations of msbuild.exe were needed to ensure that incremental restore+builds produce the correct output.

If you want to use a CI build project with PackageReference, the safest way is to create a build.proj that has a restore and a build target:

<Project>
  <Target Name="Restore">
    <MSBuild Projects="$(root)\src\MySolution.sln" Targets="Restore" />
  </Target>
  <Target Name="Build">
    <MSBuild Projects="$(root)\src\MySolution.sln" Targets="Build" />
  </Target>
</Project>

And execute it using

msbuild /restore /t:Build build.proj


回答2:

I found that calling nuget restore MySolution.sln will restore the packages for a solution.

I put nuget.exe in my build folder, and run restore for each solution in my source tree.

My MsBuild target to restore packages for all projects in all solutions.

<Target Name="NuGetRestore">
  <ItemGroup>
    <slns Include="$(MSBuildProjectDirectory)\..\**\*.sln"/>
  </ItemGroup>
  <Exec Command="$(MSBuildProjectDirectory)\nuget restore %(slns.Identity)"/>
</Target>

Nuget.exe doesn't have to be in each project folder, just in the folder with build.



回答3:

I also ran into the issue of MSBuild not pulling the packages. I added the path nuget.config file using RestoreConfigFile to the properties parameter

RestoreConfigFile=$(MSBuildStartupDirectory)\.nuget\nuget.config

and also changed the Targets value on the MSBuild task:

MSBuild Targets="Restore;Clean;Build" Projects=...

The Restore target actually forced the pulling of the packages and the RestoreConfigFile pointed it to my settings.