Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trying to load a project with Sdk.WindowDesktop fails. #120

Open
vpenades opened this issue Jan 18, 2021 · 3 comments
Open

Trying to load a project with Sdk.WindowDesktop fails. #120

vpenades opened this issue Jan 18, 2021 · 3 comments

Comments

@vpenades
Copy link

vpenades commented Jan 18, 2021

I've been trying to load a csproj using new Microsoft.Build.Evaluation.Project("project.csproj", null, null"); and it throws this exception:

The specified SDK "Microsoft.NET.Sdk.WindowsDesktop" could not be found.
Source: Microsoft.Build
Error: MSB4236
MSBuild.CouldNotResolveSdk

The loaded csproj looks like this:

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">

  <PropertyGroup>
    <TargetFramework>net471</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

</Project>

And the host application registers the MSBuild location with:

Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults();

I've noticed different behavior depending on whether the host application is compiled against Net472 or against NetCoreApp31:

On Net472

  • The Microsoft.NET.Sdk.WindowsDesktop projects succeeds to load.
  • MSBuildPath of Locator Instance points to: "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin"

On NetCoreApp3.1

  • The Microsoft.NET.Sdk.WindowsDesktop projects throw an exception on load.
  • MSBuildPath of Locator instance points to: "C:\Program Files\dotnet\sdk\2.2.300"
    On Net4xx:

So I believe this is the reason because it works on Net4 and not on NetCore.

Is there a way to solve this issue and make the "Microsoft.NET.Sdk.WindowsDesktop" projects to load while the host app is NetCoreApp?

@ghelyar
Copy link

ghelyar commented Nov 9, 2021

This is not a particularly nice workaround because it makes the library pretty pointless, as you have to tell the "locator" library exactly where to look, but you can do this from a .NET Core app (on Windows), and it will be able to load both .NET Core and .NET Framework projects:

MSBuildLocator.RegisterMSBuildPath(@"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin");

Seems that DiscoveryType.DeveloperConsole and DiscoveryType.VisualStudioSetup only work on the .NET Framework version of this package, and DiscoveryType.DotNetSdk only works on the .NET Core version of this package, so this returns completely different results depending on the target framework of the project that is referencing the package:

foreach (var instance in MSBuildLocator.QueryVisualStudioInstances(
    new VisualStudioInstanceQueryOptions
    {
        DiscoveryTypes = DiscoveryType.DeveloperConsole | DiscoveryType.DotNetSdk | DiscoveryType.VisualStudioSetup
    }))
{
    Console.WriteLine($"{instance.DiscoveryType} {instance.MSBuildPath}");
}

But if you take the paths from either of them and just pass them to MSBuildLocator.RegisterMSBuildPath, they work in the other, so it's a bit annoying that it doesn't just find all the same paths regardless of target framework. You can specify DiscoveryType but it's mostly pointless, because it ignores it when finding them, and then only uses it to throw away results afterwards.

@vpenades
Copy link
Author

The problem with that approach is that our project runs on different environments, and it's not guaranteed the path to pass to RegisterMSBuildPath is the same on all machines (specially those with different versions of VS)

@ghelyar
Copy link

ghelyar commented Nov 12, 2021

Yes, it's not ideal, and I'm not making any excuses for this library. I'm just a consumer of this library, and I'm sharing my workaround.

Exactly how you get the path to the directory containing msbuild will depend on your environments. For my usage, I can just pass it in as an argument. You might be able to search your path environment variables, or use where.exe msbuild to find it, or save it to an environment variable on the machine, or you might be able to do something like this:

var msbuildDirectories = new[]
    {
        @"C:\Program Files (x86)\Microsoft Visual Studio",
        @"C:\Program Files\Microsoft Visual Studio"
    }
    .Where(Directory.Exists)
    .SelectMany(path => Directory.EnumerateFiles(path, "msbuild.exe", SearchOption.AllDirectories))
    .Select(Path.GetDirectoryName);

Two overloads exist:

  • MSBuildLocator.RegisterMSBuildPath(string)
  • MSBuildLocator.RegisterMSBuildPath(string[])

So you could either .ToArray() this or .First() it or .Last() it etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants