3
votes

I'm attempting to set up an Azure DevOps build pipeline against a .NET Framework 4.7.2 solution which contains a Visual Studio Installer Project. I've set up a self-hosted agent on a Windows Server 2019 VM, which has Visual Studio 2019 Community installed. The build pipeline contains the NuGet Installer task, followed by the NuGet task, set up to restore the referenced NuGet Packages. Below is the YAML snippet:

- task: NuGetCommand@2
  inputs:
    command: 'restore'
    restoreSolution: '$(solution)'

Running a build with this configuration however, results in the following error in the build logs:

[error]The nuget command failed with exit code(1) and error(C:\##############.vdproj(1,1): error MSB4025: The project file could not be loaded. Data at the root level is invalid. Line 1, position 1.)

This appears to be due to a performance enhancement that's been made in newer versions of nuget.exe. The suggestion, based on this GitHub issue, is to enable skipping non-existent package targets using the RestoreUseSkipNonexistentTargets MSBuild setting.

The GitHub issue mentions using the NUGET_RESTORE_MSBUILD_ARGS NuGet CLI environment variable in order to set this property, but I don't know how this can be achieved through the NuGet build task.

Since NuGet is now integrated with MSBuild, I then attempted to set this property to false through a command-line argument on the NuGet task. I modified the YAML, setting the command to custom in order to pass arguments. I based the syntax off of the MSBuild restore documentation. It now looks like follows:

- task: NuGetCommand@2
  inputs:
    command: 'custom'
    arguments: 'restore "$(solution)" -p:RestoreUseSkipNonexistentTargets=false'

This build configuration results in the following error:

[error]The nuget command failed with exit code(1) and error(Unknown option: '-p:RestoreUseSkipNonexistentTargets=false')

My question is, how do I go about getting the NuGet restore task to skip package restore on .vdproj projects?

EDIT

The other project in the solution is a C# WinForms .NET Framework project. We're using packages.config rather than PackageReference.

2
Apart from the installer project, what's the info about other projects? All C#/VB projects? Using PackageReference or Packages.config?LoLance
@LanceLi-MSFT The only other project is a C# WinForms app, using packages.config. Have edited the question for clarity.Carl Heinrich Hancke
Hi friend, you need a command like this: nuget restore proj1\packages.config -PackagesDirectory ..\packages . See here.LoLance
Apart from restoring packages for whole solution, you can restore for one separate project. For your situation, this can be more suitable. And for the reason why ` arguments: 'restore "$(solution)" -p:RestoreUseSkipNonexistentTargets=false'` not works, nuget restore command can't recognize the msbuild property.LoLance
Thanks @LanceLi-MSFT, I will try doing that. For this example solution the above should be fine to use, but I wonder when using a solution with dozens of projects, whether the above approach would scale well? Could I perhaps replace the NuGet task with the MSBuild task & do the restore through there? I noticed ADO says this approach is deprecated, but it may be more robust on big solutions or when new projects are added.Carl Heinrich Hancke

2 Answers

2
votes

As for your original issue: MSB4025

As you mentioned above, it's one open issue here. Anyone interested at it can track the issue there.

[error]The nuget command failed with exit code(1) and error(Unknown option: '-p:RestoreUseSkipNonexistentTargets=false')

The nuget restore command won't recognize a msbuild property. See similar issue and more details here.

Since The other project in the solution is a C# WinForms .NET Framework project. We're using packages.config rather than PackageReference.

A workaround for this is to use nuget custom command like this:

- task: NuGetCommand@2
  inputs:
    command: 'custom'
    arguments: 'restore YourProjectName\packages.config -PackagesDirectory $(Build.SourcesDirectory)\packages'

This can skip the restore step for the installer project.

0
votes

In general you do not need to called nuget restore explicitly anymore. MSBuild does it automatically as part of the build (so you're likely doing it twice). You can add the p:RestoreUseSkipNonexistentTargets=false property to the MSBuild arguments of a VSBuild task or a DotNet build or publish task:

- task: DotNetCoreCLI@2
  displayName: Build/Publish
  inputs:
    command: 'publish'
    publishWebProjects: false
    projects: '$(solution)'
    arguments: '-r $(runtimeIdentifier) /p:RestoreUseSkipNonexistentTargets=false'
    zipAfterPublish: false
    modifyOutputPath: false