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

MSBuildWorkspace: Loading a solution with a ProjectReference prevents compilation #36072

Open
rowland-banks-abide opened this issue May 30, 2019 · 23 comments
Labels
Area-IDE Bug help wanted The issue is "up for grabs" - add a comment if you are interested in working on it IDE-MSBuildWorkspace MSBuildWorkspace
Milestone

Comments

@rowland-banks-abide
Copy link

Version Used:
Microsoft.Build.Locator v1.2.2
Microsoft.CodeAnalysis v3.1.0
Microsoft.CodeAnalysis.Workspaces.MSBuild v3.1.0

Steps to Reproduce:

See attached "RoslynTest.zip" for Zip file demonstrating problem. Unzip to C:\Source (or modify the code to point to correct location) and run RoslynTest.sln

RoslynTest.zip

  1. Create a solution containing two netstandard2.0 libraries (A and B). Each solution should have a simple class in it.
  2. Execute the code below, and note that both projects compile.
  3. Add a ProjectReference so that B depends on A.
  4. Execute the code below and note that only project A compiles.
static async Task Main(string[] args)
{
    MSBuildLocator.RegisterDefaults();
    using (var workspace = MSBuildWorkspace.Create())
    {
        workspace.WorkspaceFailed += (sender, workspaceFailedArgs) => WriteLine(workspaceFailedArgs.Diagnostic.Message);
        var solution = await workspace.OpenSolutionAsync(@"c:\source\ForRoslynTest\ForRoslynTest.sln");
        WriteLine($"Loaded solution {solution.FilePath}");

        var projectTree = workspace.CurrentSolution.GetProjectDependencyGraph();
        foreach (var projectId in projectTree.GetTopologicallySortedProjects())
        {
            await CompileProject(workspace.CurrentSolution.GetProject(projectId));
        }
    }
}

private static async Task CompileProject(Project project)
{
    WriteLine($"Compiling {project.Name}. It has {project.MetadataReferences.Count} metadata references.");
    var compilation = await project.GetCompilationAsync();
    var errors = compilation.GetDiagnostics().Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error);
    if (errors.Any())
    {
        WriteLine($"COMPILATION ERROR: {compilation.AssemblyName}: {errors.Count()} compilation errors: \n\t{string.Join("\n\t", errors.Where(e => false).Select(e => e.ToString()))}");
    }
    else
    {
        WriteLine($"Project {project.Name} compiled with no errors");
    }
}

Expected Behavior:
Both projects compile with 0 errors.

Actual Behavior:
Project B fails to compile. In addition, project B reports that it has 0 Metadata references (whereas it has 113 without the PackageReference)

In particular, I note the following output reported:

Msbuild failed when processing the file 'c:\source\ForRoslynTest\DownstreamLibrary\DownstreamLibrary.csproj' with message: C:\Program Files\dotnet\sdk\2.1.602\Microsoft.Common.CurrentVersion.targets: (1548, 5): The "Microsoft.Build.Tasks.ResolveNonMSBuildProjectOutput" task could not be loaded from the assembly Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.  Confirm that the <UsingTask> declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.

Found project reference without a matching metadata reference: c:\source\ForRoslynTest\CoreLibrary\CoreLibrary.csproj

Loaded solution c:\source\ForRoslynTest\ForRoslynTest.sln

Compiling CoreLibrary. It has 113 metadata references.
Project CoreLibrary compiled with no errors

Compiling DownstreamLibrary. It has 0 metadata references.
COMPILATION ERROR: DownstreamLibrary: 3 compilation errors:
        c:\source\ForRoslynTest\DownstreamLibrary\Class1.cs(1,7): error CS0246: The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?)
        c:\source\ForRoslynTest\DownstreamLibrary\Class1.cs(5,18): error CS0518: Predefined type 'System.Object' is not defined or imported
        c:\source\ForRoslynTest\DownstreamLibrary\Class1.cs(5,18): error CS1729: 'object' does not contain a constructor that takes 0 arguments
@rowland-banks-abide
Copy link
Author

rowland-banks-abide commented May 30, 2019

Using Procmon, I believe it is reading the Microsoft.Build.Tasks.Core assembly from C:\Program Files\dotnet\sdk\2.1.602\Microsoft.Build.Tasks.Core.dll.

Interestingly, when I decompile this with ILSpy, I find that the ResolveNonMSBuildProjectOutput class does not exist - I suspect this is the root of my problem.

The version of the DLL is 15.1.0.0 but the assembly file version is 16.0.450.56488.

I have older versions of 15.1.0.0 of this DLL on my machine (e.g 15.1.1012.6693) that do have this class in place.

EDIT
I've just upgraded to 2.2.300 and confirmed that the same issue is in place (except now slightly worse as it's complaining that it can't find Newtonsoft.Json v9.0.0.0, as the version in the dotnet\sdk\2.2.300 folder is 10.0.0.0. I can fix that by installing Newtonsoft.Json v9.0.1 into my RoslynTest project, and then I'm back to the reported issue)

@rowland-banks-abide
Copy link
Author

I've discovered that if I change the TargetFramework of RoslynTest project to net472, rather than netcoreapp2.1 it works.

I've posted this as a Stack Overflow question as well:

@vatsalyaagrawal vatsalyaagrawal added Area-IDE IDE-MSBuildWorkspace MSBuildWorkspace Bug help wanted The issue is "up for grabs" - add a comment if you are interested in working on it labels Jun 6, 2019
@vatsalyaagrawal vatsalyaagrawal added this to the Backlog milestone Jun 6, 2019
@daniel-munch-cko
Copy link

Running into this exact behaviour as well - Is there any updates on it? Thanks!

@daniel-munch-cko
Copy link

This comment maca88/AsyncGenerator#24 (comment) suggests setting BuildingInsideVisualStudio to false.

However, if I create a workspace like this

var workspace = MSBuildWorkspace.Create(new Dictionary<string, string>() {
  { "BuildingInsideVisualStudio", "false" }
});

I'm running into the following exception

Unhandled Exception: System.ArgumentException: An element with the same key but a different value already exists. Key: BuildingInsideVisualStudio
   at System.Collections.Immutable.ImmutableDictionary`2.HashBucket.Add(TKey key, TValue value, IEqualityComparer`1 keyOnlyComparer, IEqualityComparer`1 valueComparer, KeyCollisionBehavior behavior, OperationResult& result)
   at System.Collections.Immutable.ImmutableDictionary`2.AddRange(IEnumerable`1 items, MutationInput origin, KeyCollisionBehavior collisionBehavior)
   at System.Collections.Immutable.ImmutableDictionary`2.AddRange(IEnumerable`1 pairs, Boolean avoidToHashMap)
   at System.Collections.Immutable.ImmutableDictionary`2.AddRange(IEnumerable`1 pairs)
   at Microsoft.CodeAnalysis.MSBuild.Build.ProjectBuildManager.StartBatchBuild(IDictionary`2 globalProperties) in /_/src/Workspaces/Core/MSBuild/MSBuild/Build/ProjectBuildManager.cs:line 152
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.LoadAsync(CancellationToken cancellationToken) in /_/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.Worker.cs:line 133
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.LoadSolutionInfoAsync(String solutionFilePath, IProgress`1 progress, CancellationToken cancellationToken) in /_/src/Workspaces/Core/MSBuild/MSBuild/MSBuildProjectLoader.cs:line 199
   at Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace.OpenSolutionAsync(String solutionFilePath, IProgress`1 progress, CancellationToken cancellationToken) in /_/src/Workspaces/Core/MSBuild/MSBuild/MSBuildWorkspace.cs:line 183
   at checkout_ap_analyzer.Program.ExecuteLogAnalysis(String solutionFile) in /Users/daniel.munch/Projects/checkout-ap-analyzer/Program.cs:line 64
   at checkout_ap_analyzer.Program.Main(String[] args) in /Users/daniel.munch/Projects/checkout-ap-analyzer/Program.cs:line 24
   at checkout_ap_analyzer.Program.<Main>(String[] args)

@ionoy
Copy link

ionoy commented Jul 31, 2019

@daniel-munch-cko Same here. I even tried overriding default properties with reflection, but it still fails to build with the following message:

The "ResolvePackageAssets" task failed unexpectedly. System.IO.FileLoadException: Could not load file or assembly 'NuGet.Frameworks, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Could not find or load a specific file. (Exception from HRESULT: 0x80131621)

I really need this functionality... If anyone finds a workaround, please post it here.

@daniel-munch-cko
Copy link

daniel-munch-cko commented Jul 31, 2019

On my Mac I ended up using mono to run my application on full .net472 which works (just like mentioned by the original author of this issue), but admittedly this is a bit annoying since it alters my full .NET Core experience.

@ionoy
Copy link

ionoy commented Jul 31, 2019

Unfortunately, my application targets Core and I can't use .net472. I could probably create an external console application that would send me the required data, but it's a terrible solution compared to in-process analysis.

Now I'm more interested to know if this issue is solvable at all or is it a dead-end.

@daniel-munch-cko
Copy link

I see, yeah that's indeed a terrible workaround.

My next attempt would have been to file a similar issue (or to link this issue) in the MSBuildLocator repository here: /~https://github.com/microsoft/MSBuildLocator/

That's without evidence, but the error message seems to suggest troubles in locating an assembly, which is exactly what the MSBuildLocator is dealing with. It might be worth having a closer look what it does and if this issue actually belongs rather to them than to Roslyn itself.

@ionoy
Copy link

ionoy commented Aug 1, 2019

It's my understanding that MSBuildLocator works correctly by locating the Core SDK. The issue is that Core SDK can't build non-Core projects anymore (if it ever could). So, in its' current state, MSBuildWorkspace only works for building .NET Core projects. Maybe this was intended from the beginning.

@huancz
Copy link

huancz commented Aug 1, 2019

What led me to this report - I was trying to build (netcore) console analyzer for another netcore project. At least it was easy to switch the analyzer to 4.7.2. Whatever SDK MSBuildLocator locates should be able to work in that scenario...

@ionoy
Copy link

ionoy commented Aug 9, 2019

@daniel-munch-cko I ported my console app to net472 and while executing it on Mono I get PlatformNotSupportedException from MSBuildLocator.RegisterDefaults() call. (microsoft/MSBuildLocator#72)

Did you encounter anything similar?

@InfinitiesLoop
Copy link

Same problem here. I'm trying to build .NET core app that runs analysis on a non-core .NET app. It's a unity project, so can't just change that -- unity generates a sln and csproj's. If I run the exact same code as a .NET 4.7 console app, it works fine. Would love to hear from someone whether the scenario I am going for is even supported or if this is a legitimate bug.

@daniel-munch-cko
Copy link

daniel-munch-cko commented Aug 26, 2019

Sorry @ionoy realised I forgot to reply - I think I saw something similar, I explicitly registered the Mono MSBuild path using this line

MSBuildLocator.RegisterMSBuildPath("/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/msbuild/15.0/bin/");

@ionoy
Copy link

ionoy commented Aug 26, 2019

@daniel-munch-cko I did that too, but it didn't help. There was a new error on constructing MSBuildWorkspace, something with reflection and Sqlite.raw. Ultimately I switched to AdHocWorkspace and .NET Core, which worked like a charm. Although, this solution requires the knowledge of all references and source files.

@daniel-munch-cko
Copy link

I think I ran into the same issue with Sqlite.raw - manually adding a NuGet reference to SQLitePCLRaw.core fixed it for me as far as I can remember

@ErikSchierboom
Copy link

Although, this solution requires the knowledge of all references and source files.

This is what I don't like about that approach. It's slightly odd to me that compiling a .NET Core project such a hassle. Is this really an unsupported use case, or does anyone have an example?

@ddizh
Copy link

ddizh commented Sep 26, 2019

I've also faced the same issue trying to load nectoreapp2.1 *.csproj with three netstandard2.0 project references on OSx.

@rainersigwald
Copy link
Member

Same problem here. I'm trying to build .NET core app that runs analysis on a non-core .NET app. It's a unity project, so can't just change that -- unity generates a sln and csproj's. If I run the exact same code as a .NET 4.7 console app, it works fine. Would love to hear from someone whether the scenario I am going for is even supported or if this is a legitimate bug.

@InfinitiesLoop No, that's not a supported scenario. .NET Core MSBuild doesn't support every operation that full .NET Framework MSBuild.exe does, and has a different extensibility model (Visual Studio allows extensions to add MSBuild logic, which isn't available to .NET Core MSBuild).

As a result of that, some projects can only be built with full framework MSBuild, so an application that wants to use the MSBuild API for them (including indirectly through MSBuildWorkspace) must target .NET Framework and use full-framework MSBuild.

@d-dizhevsky Looking through this thread, I see several related issues. Can you be explicit about what problem you have?

@ddizh
Copy link

ddizh commented Sep 27, 2019

@rainersigwald
I have created repro project here: /~https://github.com/d-dizhevsky/owss

It contains:

  • src/OpenWebSecurityScanner project which targets netcoreapp2.1 and runs MSBuildWorkspace
  • testProjects/WebAPI1 which was created with dotnet new webapi
  • testProjects/TestCoreLib which was created with dotnet new classlib

The WebAPI1 has a project reference on TestCoreLib.
Just do cd src/OpenWebSecurityScanner/ and then dotnet run.

Thats my output on OSx:
image

Please note that if you remove TestCoreLib project reference from WebAPI1 then it works properly.

@rainersigwald
Copy link
Member

@d-dizhevsky Thanks! I opened dotnet/msbuild#4770 to track fixing that problem.

Setting BuildingInsideVisualStudio would indeed disable the call to that task, but I think it might break other parts of design-time-like builds, even beyond the ImmutableDictionary exception mentioned above.

@pkrukp
Copy link

pkrukp commented Dec 23, 2019

I have similar problem - I have .net framework application which tries to open a .net core project using msbuild api (to later use roslyn analysis). Opened project contains error diagnostics. What's interesting, if I run Debug>Run Debugging, the problems disappear.

I filed a bug for msbuild, but maybe this is more roslyn related?
dotnet/msbuild#5002

@miyu
Copy link

miyu commented Apr 8, 2020

== Emphasis for MS devs before wall-of-text manual workaround: there's a manual workaround, but this bug is NOT user error and likely affects a significant number of .net core deployments using Roslyn. It LIKELY either has to do with a mix of VS deployment version & MSBuild loading an old .NET Core SDK.

The bug likely manifests in many other ways. For example, it caused my Roslyn setup to fail to resolve float symbol via GetSymbolInfo(someFloatTypeSyntax).

I found a manual workaround to this WorkspaceFailed error:

[Failure] Msbuild failed when processing the with message: The "Microsoft.Build.Tasks.ResolveNonMSBuildProjectOutput" task could not be loaded from the assembly Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a. Confirm that the declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.

There were a few resolution steps:

  1. following Design-time build tasks aren't all available in .NET Core msbuild#4770 I updated VS 2019 from 16.2 to 16.5.3... This didn't fix my bug, but it's worth documenting I did this.
  2. I upgraded my Microsoft.Build.* and Microsoft.CodeAnalysis dependencies to latest, THIS DIDN'T FIX THINGS YET, same bug.
  3. I navigated to C:\Program Files\dotnet\sdk which previously had a few directories:
1.0.0/                  1.0.0-rc4-004771/  2.0.3/    2.1.505/
1.0.0-preview1-002702/  1.0.3/             2.1.202/  3.1.100/
1.0.0-preview2-003121/  1.0.4/             2.1.4/    3.1.201/
1.0.0-preview4-004233/  1.1.0/             2.1.502/  NuGetFallbackFolder/
  1. I renamed this to sdk_o and created a new folder C:\Program Files\dotnet\sdk, copying in only 3.1.201/

Success! This error was gone, but running my roslyn app then resulted in some error like (paths stripped)

[Failure] Msbuild failed when processing the file with message The "ProcessFrameworkReferences" task failed unexpectedly. System.IO.FileNotFoundException: Could not load file or assembly 'NuGet.Frameworks, Version=5.5.0.4, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified. File name: 'NuGet.Frameworks, Version=5.5.0.4, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

Solved this one by adding NuGet.ProjectModel 5.5.1 to my project, the csproj now has the following package references:

   <ItemGroup>
     <PackageReference Include="Microsoft.Build" Version="16.5.0" ExcludeAssets="runtime" />
     <PackageReference Include="Microsoft.Build.Framework" Version="16.5.0" ExcludeAssets="runtime" />
     <PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
     <PackageReference Include="Microsoft.Build.Tasks.Core" Version="16.5.0" ExcludeAssets="runtime" />
     <PackageReference Include="Microsoft.CodeAnalysis" Version="3.5.0" />
     <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.5.0" />
     <PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.5.0" />
     <PackageReference Include="NuGet.ProjectModel" Version="5.5.1" />
   </ItemGroup>

No more WorkspaceFailed events for this code:

Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults();
var workspace = MSBuildWorkspace.Create();
workspace.WorkspaceFailed += (s, e) => { Console.WriteLine(e.Diagnostic); };
var project = await workspace.OpenProjectAsync(@"C:/path/to.csproj");     

My csproj looks as follows:

<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
      <TargetFramework>netcoreapp3.1</TargetFramework>
      <UseWindowsForms>true</UseWindowsForms>
      <OutputType>Library</OutputType>
      <ApplicationIcon />
      <StartupObject />
   </PropertyGroup>

   <ItemGroup>
      <ProjectReference Include="..\..\dependencies\some.csproj" />
   </ItemGroup>
</Project>

miyu added a commit to miyu/OpenMOBA that referenced this issue Apr 8, 2020
See dotnet/roslyn#36072 (comment)

MSBuild had a bug which made Roslyn unable to successfully load
projects. This led to Roslyn being unable to resolve types like `float`
to sdk framework assemblies.
@rainersigwald
Copy link
Member

rainersigwald commented Apr 9, 2020

running my roslyn app then resulted in some error like (paths stripped)

[Failure] Msbuild failed when processing the file with message The "ProcessFrameworkReferences" task failed unexpectedly. System.IO.FileNotFoundException: Could not load file or assembly 'NuGet.Frameworks, Version=5.5.0.4, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified. File name: 'NuGet.Frameworks, Version=5.5.0.4, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

Solved this one by adding NuGet.ProjectModel 5.5.1 to my project

This is a result of microsoft/MSBuildLocator#86, so we should be able to avoid the need for that reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE Bug help wanted The issue is "up for grabs" - add a comment if you are interested in working on it IDE-MSBuildWorkspace MSBuildWorkspace
Projects
Status: InQueue
Development

No branches or pull requests