Home: MSBuild auto-detection always selects 16.0 after installing VS 2019 Preview

Created on 11 Dec 2018  路  17Comments  路  Source: NuGet/Home

Last week I installed VS 2019 Preview. Since installing the Preview, NuGet.exe always picks version '16.0.218.25180' regardless of which Developer Command Prompt I use. This seems similar to some issues reported in the past with previous Visual Studio Preview versions but I haven't found any reports yet for VS 2019.

This is specifically causing problems when trying to restore packages from the VS 2017 Developer Command Prompt for projects that use MSBuild variables like$(MSBuildExtensionsPath32) along with $(VisualStudioVersion) to compose paths. The main offender of this is Microsoft.WebApplication.targets. Since I'm using a VS 2017 Developer Command Prompt, %VisualStudioVersion% is "15.0" so $(VisualStudioVersion) is 15.0. But since NuGet is picking MSBuild 16.0, variables like $(MSBuildExtensionsPath32) are things like C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild. Combining these two paths leads to paths that don't exist, causing the project file to be invalid, causing the restore to fail.

I've tried using NuGet 4.8.1, 4.9.1, and the latest version of the 5.0.0 preview (1.5718) and they all have this issue when run from the VS 2017 Developer Command Prompt:

>nuget-4.8.1-latest.exe help
NuGet Version: 4.8.1.5435
<snip>

>nuget-4.8.1-latest.exe restore MyProj.csproj
MSBuild auto-detection: using msbuild version '16.0.218.25180' from 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\bin'.
MyProj.csproj(384,11): error MSB4226: The imported project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Microsoft\VisualStudio\v15.0\WebApplications\Microsoft.WebApplication.targets" was not found. Also, tried to find "WebApplications\Microsoft.WebApplication.targets" in the fallback search path(s) for $(VSToolsPath) - "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v15.0" . These search paths are defined in "C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\bin\msbuild.exe.Config". Confirm that the path in the <Import> declaration is correct, and that the file exists on disk in one of the search paths.

>nuget-4.9.1.exe help
NuGet Version: 4.9.1.5694
<snip>

>nuget-4.9.1.exe restore MyProj.csproj
MSBuild auto-detection: using msbuild version '16.0.218.25180' from 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\bin'.
MyProj.csproj(384,11): error MSB4226: The imported project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Microsoft\VisualStudio\v15.0\WebApplications\Microsoft.WebApplication.targets" was not found. Also, tried to find "WebApplications\Microsoft.WebApplication.targets" in the fallback search path(s) for $(VSToolsPath) - "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v15.0" . These search paths are defined in "C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\bin\msbuild.exe.Config". Confirm that the path in the <Import> declaration is correct, and that the file exists on disk in one of the search paths.

>nuget-5.0.0-preview1.5718.exe help
NuGet Version: 5.0.0.5718
<snip>

>nuget-5.0.0-preview1.5718.exe restore MyProj.csproj
MSBuild auto-detection: using msbuild version '16.0.218.25180' from 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\bin'.
MyProj.csproj(384,11): error MSB4226: The imported project "C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Microsoft\VisualStudio\v15.0\WebApplications\Microsoft.WebApplication.targets" was not found. Also, tried to find "WebApplications\Microsoft.WebApplication.targets" in the fallback search path(s) for $(VSToolsPath) - "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v15.0" . These search paths are defined in "C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\bin\msbuild.exe.Config". Confirm that the path in the <Import> declaration is correct, and that the file exists on disk in one of the search paths.

I have VS 2015, 2017, and 2019 Preview installed. Here's what I get in each Developer Command Prompt.

Developer Command Prompt for VS2015

C:\>where msbuild
C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe

C:\>msbuild /version
Microsoft (R) Build Engine version 14.0.27522.0
Copyright (C) Microsoft Corporation. All rights reserved.

14.0.27522.0

Developer Command Prompt for VS 2017

C:\>where msbuild
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild.exe
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe

C:\>msbuild /version
Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

15.9.20.62856

Developer Command Prompt for VS 2019 Preview

C:\>where msbuild
C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\Bin\MSBuild.exe
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe

C:\>msbuild /version
Microsoft (R) Build Engine version 16.0.218-preview+g5c625fa747 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

16.0.218.25180

Here's a stripped down sample of my csproj that demonstrates the issue. I'm not sure if it's an absolutely minimal repro, but it's pretty slimmed down compared to the original csproj.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <ProjectGuid>{8BBA3B75-ECBB-43FB-93A7-27FA64A9BC95}</ProjectGuid>
    <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>MyProj</RootNamespace>
    <AssemblyName>MyProj</AssemblyName>
    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
  </PropertyGroup>
  <PropertyGroup>
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>

    <!--
      The import below is what causes the problem.

      On my machine:
        $(MSBuildExtensionsPath32) = C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild
        $(VisualStudioVersion) = 15.0 when running from VS 2017 Developer Command Prompt

      This means that $(VSToolsPath) resolves to C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Microsoft\VisualStudio\v15.0\WebApplications\Microsoft.WebApplication.targets.

      When running from the VS 2017 Developer Command Prompt, the path should resolve to C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\WebApplications\Microsoft.WebApplication.targets.
    -->
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
  </PropertyGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
  <Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
    <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
  </Target>
</Project>
2 NuGet.exe Bug

Most helpful comment

Oh. I forgot to mention that I can resolve this by invoking NuGet on the command line with -MSBuildVersion 15.9. But not everybody on my team has updated to the latest MSBuild - some people still have 15.8 installed for instance.

All 17 comments

Oh. I forgot to mention that I can resolve this by invoking NuGet on the command line with -MSBuildVersion 15.9. But not everybody on my team has updated to the latest MSBuild - some people still have 15.8 installed for instance.

@JacobSnyder wow, thanks! I was having these problems since two days ago and I was going to write new issue, but you have beaten me 馃檪

Thanks for reporting this with detail repro! 馃憤

FYI, this issue won't happen if I have both VS 2017 15.8.x and VS 2017 15.9.x preview. After installing VS 2019 Preview, this issue happens and it always be reproducible.

cc @rrelyea @anangaur @nkolev92

Another workaround is to specify MSBuildPath to the correct msbuild folder like ...\msbuild\15.0\Bin which will work irrespective of the version.

The command line reference states that it uses MSBuild from path, and if it's not present, then it should use the latest version. I have my VS2017's MSBuild in path, and it is ignored.

The workaround that I've used on our project was invoking vswhere.exe to get the latest stable VS installation path and feeding its MSBuild location to NuGet via MSBuildPath parameter.

It works, but I'd rather like to get this behavior from NuGet itself.

I'm running vs2017 15.9.4, and vs2019 preview, and with nuget 4.7.1.5393 and onwards it detects msbuild from vs2019 preview.

-- 4.7.1.5393

nuget restore app.sln
MSBuild auto-detection: using msbuild version '16.0.218.25180' from 'C:\Program Files (x86)\Microsoft Visual Studio2019\Preview\MSBuild\Current\bin'.

If I use 4.8.1.5435 or 4.9.2.5706 I also get other issues:

MSBuild auto-detection: using msbuild version '16.0.218.25180' from 'C:\Program Files (x86)\Microsoft Visual Studio2019\Preview\MSBuild\Current\bin'.
myproj.csproj(106,3): error MSB4019: The imported project "C:\Program Files (x86)\Microsoft Visual Studio2019\Preview\MSBuild\Microsoft\VisualStudio\v15.0\WCF\Microsoft.VisualStudio.ServiceModel.targets" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

And yes, if I add -MSBuildVersion 15.9 to my nuget-command, everything works again, but please can this be fixed?

@neslekkim

Where are you running nuget.exe from in those case?

What would you expected nuget.exe to do when being run from:

cmd / powershell

developer command prompt

I'm using nuget in an batchfile, runnning under developer command prompt (the one for vs2017)
How is nuget detecting msbuild version?
When I'm running developer command prompt for an given studio installation, there are env variables which I thought was the source, like visualstudioversion=15, vscmd_ver=15.x.x, but that's probably not the case?

NuGet is basically using some MSBUild APIs to help it detect all the msbuild toolsets on the machine.
Then it just picks the highest one.

Would you say this is an acceptable behavior:

  • When running under a developer command prompt (which basically sets these env vars), you expect NuGet to use the msbuild version called out by those env vars.

  • When running in a cmd environment (without the msbuild identifying env vars), it works the same way it does today, it detects the latest one.

If we do want something different for the latter part, NuGet would need some sort of a heuristics to help decide which msbuild version is the most appropriate one.

Unless I'm totally off, I think the first behavior is what I would expect at least.
when running under cmd, I think it would be difficult to know what the user wants, except if the path-envvariable would point to the oldest first for instance, but probably that isn't good enough?
(I would also think that if the autodetect-message indicated how to change the behavior was included, that would help a lot)

@nkolev92 When running nuget.exe help restore (4.9.2), I can see such info:

-MSBuildVersion Specifies the version of MSBuild to be used with this command. Supported values are 4, 12, 14. By default the MSBuild in your path is picked, otherwise it defaults to the highest installed version of MSBuild.
-MSBuildPath Specifies the path of MSBuild to be used with this command. This command will takes precedence over MSbuildVersion, nuget will always pick MSBuild from this specified path.

It would be good to add versions 15 and 16, but the most important issue is ignoring the PATH environment variable, no matter if it's run from dev command prompt or not. It would be good it it used the 1st occurrence of MSBuild in PATH in case there are multiple paths. If it's no longer desired, there should be another documented environment variable to set the defaults.

Also, in my opinion, in case there's no MSBuild in PATH, it shouldn't point to any latest installation of Visual Studio, but rather to the latest stable one - the same which is given by vswhere.exe (unless explicitly told to use the prerelease version). Both NuGet and vswhere should use the same mechanisms of detecting Visual Studio and its MSBuild.

@marcinsmialek

I don't know if the help message about the msbuild version ever worked, or when it stopped working.
My guess is it became obsolete with the introduction of side-by-side versions of Visual Studio.

Also note that you can specify 15.x right now in nuget.exe, despite the help message not indicating that.
Fixing the help message is something that should be addressed in the same scope.

As far as vswhere detection goes, I agree the principles should be similar, maybe NuGet will need to start detecting the msbuild installation in a manner than allows it to understand whether it's dealing with a prerelease version.

Once have fix, consider 4.9.x as a potential release.

Also note that you can specify 15.x right now in nuget.exe, despite the help message not indicating that.
Fixing the help message is something that should be addressed in the same scope.

Just a note that the above was fixed in:
https://github.com/NuGet/NuGet.Client/commit/c4d5743f5c4be02ea7bbe6920ade2277220c607e

Keeping it open until there is a decision for 4.9.x but merged into dev for 5.0.0

I'm seeing this with NuGet version 5.7.0.6726, with Visual Studio 16.7.3 installed alongside 16.3.4.

image

We are calling MSBuild from the 16.3 installation, and it's Executing nuget restore xyz.sln. We log this. Looking at the log yields:
image

@nkolev92 said

As far as vswhere detection goes, I agree the principles should be similar, maybe NuGet will need to start detecting the msbuild installation in a manner than allows it to understand whether it's dealing with a prerelease version.

I think my preferred solution to this would be

  • nuget.exe autodetects as it does now by default
  • a commandline flag that indicates the MSBuild version should be taken from the environment if available , else autodetect

(I'm using NuGet.exe from MSBuild context: <Exec Command="nuget restore that.sln -NoCache -DirectDownload" />, as our build.proj can be driven by a developer or a Jenkins)
?

Was this page helpful?
0 / 5 - 0 ratings