microsoft / MSBuildLocator

An API to locate MSBuild assemblies from an installed Visual Studio location. Use this to ensure that calling the MSBuild API will use the same toolset that a build from Visual Studio or msbuild.exe would.
Other
212 stars 83 forks source link

MSBuildLocator looks for wrong version of msbuild #149

Closed ehsan-keshavarzian closed 2 years ago

ehsan-keshavarzian commented 2 years ago

I'm using MSBuildLocator 1.4.1 with .NET 6.0 and Visual Studio 2022. But at runtime I get the following error image

    <ItemGroup>
        <PackageReference Include="Microsoft.Build" Version="17.0.0" ExcludeAssets="runtime" />
        <PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.0.0" ExcludeAssets="runtime" />
        <PackageReference Include="NuGet.PackageManagement" Version="6.0.0" />
        <PackageReference Include="System.Net.Http" Version="4.3.4" />
        <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
        <PackageReference Include="Microsoft.Build.Locator" Version="1.4.1" />
    </ItemGroup>
rainersigwald commented 2 years ago

Can you provide some more details? What is the call stack of the failure? How are you registering the instance with MSBuildLocator?

ehsan-keshavarzian commented 2 years ago

StackTrace is: image

And the registration is: image image

ChristofferGersen commented 2 years ago

I had the same exception, but I figured out that I need to call MSBuildLocator.RegisterDefaults() earlier, see Docs. In my case I was calling RegisterDefaults from a static class constructor, and I was using MSBuild inside the instance constructor. So apparently this is not enough to meet the "Register instance before calling MSBuild" requirement. In your case I suspect that using MSBuild from a lambda within the same method does not meet the requirement either. Once I moved the MSBuildLocator.RegisterDefaults() call to the main method of the application, then the exception no longer occurred.

This however caused the MSBuild of .NET Core SDK 6.0.101 to be used and not the one of Visual Studio 2022. This is probably because on my system running MSBuildLocator.QueryVisualStudioInstances(VisualStudioInstanceQueryOptions.Default).ToList() results in two instances ".NET Core SDK 6.0.101" and ".NET Core SDK 3.1.416".

Running MSBuildLocator.QueryVisualStudioInstances(new VisualStudioInstanceQueryOptions() { DiscoveryTypes = DiscoveryType.VisualStudioSetup }).ToList() results in an empty list for me. I discovered that the VisualStudioLocationHelper class is only included for .Net Framework 4.6, because of the following code in Microsoft.Build.Locator.csproj

  <PropertyGroup Condition="'$(TargetFramework)'=='net46'">
    <DefineConstants>$(DefineConstants);FEATURE_VISUALSTUDIOSETUP</DefineConstants>
  </PropertyGroup>

Since I am using .Net 6 the TargetFramework is netcoreapp2.1 instead of net46. As a workaround I did the following:

  1. Install the Microsoft.VisualStudio.Setup.Configuration.Interop NuGet package in your project (I used the latest version)
  2. Copy the source of the VisualStudioLocationHelper class to your own project
  3. Remove #if/#endif lines
  4. Use reflection to create the VisualStudioInstance instance, because the constructor is internal
  5. Use MSBuildLocator.RegisterInstance(VisualStudioLocationHelper.GetInstances().First()) to register MSBuild instead of RegisterDefaults;

This seems to work for me, but I do not know if I will run into trouble later. Is it by-design that you cannot use the MSBuild of Visual Studio 2022 when targeting .Net 6 yourself or is this a bug? In other words, is it required to keep targeting .Net Framework instead of .Net (Core), when you want to use the MSBuild of Visual Studio 2022?

ehsan-keshavarzian commented 2 years ago

Thanks for the hint. I moved the registration to main and it works now. BTW, I'm using .NET 6.0 and not .NET Framework.

I am getting a new exception which is not related to this, so I'm going to post it somewhere else. But here it is just for the reference:

image