I'm posting this issue to respond to many issues that can be resolved by this way.
So the problem for me was that when i open a solution, the metadataReferences was always empty and the diagnostics had many issues like "PredefinedType System.Object is not defined".... After days of investigating :/ the problem was the version of the dll Microsoft.Build.Framework used, because even if you update the nuget package, your program will be using whatever version installed in your GAC (C:\Windows\Assembly...) which is usually an old version that's causing all these problems. So you should redirect that version in the app.config (or web.config ☺)like bellow:
Of course 15.1.0.0 is whatever version you installed via nuget ☺.
Yes, a number of people run into this.
Here's a recent instance.
Tagging @DustinCampbell who understands the issue better than I do.
Yes too bad i didn't fing that answer earlier :/
But you should not bind redirect all those packages, but only those that already exist in the GAC (for me Microsoft.Build.Utilities.Core, Microsoft.Build.Tasks.Core, and ofc Microsoft.Build.Framework)
@jcouv's workaround got me up and running:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Tasks.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Build.Utilities.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-99.9.9.9" newVersion="15.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
@jnm2 yes it will. But the newVersion should be the version of the dll you installed. which is 15.1.0.0 if you installed the latest nuget package for now
@RipPer56 Yes, did I do that wrong?
If it worked means no. But if you update the Microsoft.Build nuget package some days, you'll have to change the 15.1.0.0 to the newer version
@RipPer56: To clarify, you're seeing this issue when using MSBuildWorkspace, correct?
Yeap exactly
Thanks @RipPer56. The problem is that the package that includes MSBuildWorkspace ends up pulling on the Microsoft.Build.* assemblies into your application. So, these assemblies end up getting loaded into your application but the MSBuild toolset (e.g. all of the MSBuild tasks found in Visual Studio) are built against a different set of Microsoft.Build.* assemblies. This results in all sorts of problems.
The solution is to delete the Microsoft.Build.* from your build output and then use the Microsoft.Build.Locator package to register an instance of MSBuild from a Visual Studio 2017 install on your machine. This will install an AppDomain.AssemblyResolve hook that loads the Microsoft.Build.* from the registered location. So, the MSBuild toolset will get the assemblies that they expect and things will be happy.
Take a look at my reply here for more detail: https://github.com/dotnet/roslyn/issues/26029#issuecomment-380164421.
Also, in that issue, the customer created a GitHub repo demonstrating the problem. I went ahead and submitted a PR that shows how to fix the issue in that repo here: https://github.com/FizzerWL/ErrorRepro/pull/1. I hope that PR will be instructive to you too.
Thanks @DustinCampbell
If I want my tool to work on machines that don't have VS installed, I suppose continuing with the binding redirects is the best option?
@jnm2 If you don't have VS installed MSBuild needs to come from somewhere. You could deploy it as part of you application. What is your scenario?
The scenario is analysis of internal projects and dependencies across repositories and branches. The Locator solution is good enough for now, but the concept of making the tool's behavior dependent on global machine state is so distasteful to me that handcrafted binding redirects seem a small price to pay.
@jnm2 i agree with you, that's what i'm doing too. It's helpful also to get the right version of Microsoftt.Build.*
Unfortunately, this is beyond the scope of what we can do here. MSBuild is a very complicated application and depends on a plethora of tasks, targets, SDKs, etc. to process your project. When you deploy Microsoft.Build, you're really just deploying the MSBuild engine -- not everything needed to actually load and process any project. It is possible to deploy everything you need from MSBuild with your application, but it's pretty challenging (on the scale of creating your own .NET Core SDK). If you'd like a better solution, I'd recommend filing an issue over at https://github.com/Microsoft/msbuild.
MSBuildWorkspace has always (since it's initial release many years ago) required MSBuild to actually be installed on the machine that it's running on. Before MSBuild 15, it was simpler because Visual Studio installed MSBuild to the GAC. However, since MSBuild 15 is side-by-side, that's no longer possible.
FWIW, I've written up an article on how to be successful with MSBuildWorkspace and the Locator here: https://gist.github.com/DustinCampbell/32cd69d04ea1c08a16ae5c4cd21dd3a3.
I'm closing this issue because there's really nothing more we can do in the Roslyn repo.