dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
18.99k stars 4.03k forks source link

Cannot use MSBuildWorkspace in net46 xunit/mstest test assembly #17705

Open fubar-coder opened 7 years ago

fubar-coder commented 7 years ago

Version Used:

Steps to Reproduce:

Either:

  1. Create a xUnit or component test project (.NET Core)
  2. Change TargetFramework from netcoreapp1.1 to net46
  3. Add Microsoft.CodeAnalysis version 2.0.0 to the unit test project
  4. Create the MSBuildWorkspace in the test method using MSBuildWorkspace.Create();
  5. Run the unit tests

Or:

  1. Create a .NET Framework class library (net46)
  2. Add either xUnit or MSTest 1.1.13 packages
  3. Add Microsoft.CodeAnalysis version 2.0.0 to the unit test project
  4. Create the MSBuildWorkspace in the test method using MSBuildWorkspace.Create();
  5. Run the unit tests

Expected Behavior:

No error

Actual Behavior:

A System.Reflection.ReflectionTypeLoadException is thrown. The LoaderExceptions contains the following fusion log:

=== Zustandsinformationen vor Bindung ===
LOG: DisplayName = System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 (Fully-specified)
LOG: Appbase = file:///c:/users/mark/documents/visual studio 2017/Projects/TestRoslyn20/TestRoslyn20Tests/bin/Debug/net46
LOG: Ursprünglicher PrivatePath = NULL
Aufruf von Assembly : System.Reflection.Metadata, Version=1.4.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
===
LOG: Diese Bindung startet im default-Load-Kontext.
LOG: Die Anwendungskonfigurationsdatei wird verwendet: C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2017\ENTERPRISE\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\TESTWINDOW\vstest.executionengine.x86.exe.Config
LOG: Die Hostkonfigurationsdatei wird verwendet: 
LOG: Die Computerkonfigurationsdatei von C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config wird verwendet.
LOG: Die gleiche Bindung ist bereits aufgetreten und hat den Fehler hr = 0x80131040 verursacht.

This log shows that System.Reflection.Metadata version 1.4.1.0 tried to load System.Collections.Immutable version 1.2.0.0, but I cannot downgrade to this version, because Roslyn requires 1.2.1 (NuGet package version 1.3.1).

Stack trace:

   bei System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
   bei System.Reflection.RuntimeAssembly.get_DefinedTypes()
   bei System.Composition.Hosting.ContainerConfiguration.<WithAssemblies>b__0(Assembly a)
   bei System.Linq.Enumerable.<SelectManyIterator>d__16`2.MoveNext()
   bei System.Composition.TypedParts.TypedPartExportDescriptorProvider..ctor(IEnumerable`1 types, AttributedModelProvider attributeContext)
   bei System.Composition.Hosting.ContainerConfiguration.CreateContainer()
   bei Microsoft.CodeAnalysis.Host.Mef.MefHostServices.Create(IEnumerable`1 assemblies)
   bei Microsoft.CodeAnalysis.Host.Mef.DesktopMefHostServices.get_DefaultServices()
   bei Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace.Create()
   bei TestRoslyn20Tests.UnitTest1.Test1() in c:\users\mark\documents\visual studio 2017\Projects\TestRoslyn20\TestRoslyn20Tests\UnitTest1.cs:Zeile 14.

Upgrading the package Microsoft.Composition doesn't work, because it complains with a FileLoadException that the assembly System.Composition.TypedParts version 1.0.27.0 couldn't be loaded.

This is the stack trace:

   bei Microsoft.CodeAnalysis.Host.Mef.MefHostServices.Create(IEnumerable`1 assemblies)
   bei Microsoft.CodeAnalysis.Host.Mef.DesktopMefHostServices.get_DefaultServices()
   bei Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace.Create()
   bei TestRoslyn20Tests.UnitTest1.Test1() in c:\users\mark\documents\visual studio 2017\Projects\TestRoslyn20\TestRoslyn20Tests\UnitTest1.cs: Zeile14

Using an app.config for the test project doesn't work. The .dll.config gets copied to the output folder, but the binding redirect isn't picked up.

I think that the problem is two-fold:

  1. Microsoft/vstest requires auto generated binding redirects (similar to Microsoft/vstest#391, Microsoft/vstest#595)
  2. Roslyn is delivered with incompatible package dependencies

Fun fact: Using a .NET Framework console application works without error.

Pilchie commented 7 years ago

@tmat Do you understand the dependencies here?

Pilchie commented 7 years ago

@tmat can you help with the dependencies here?

tmat commented 7 years ago

@fubar-coder Do you have {AssemblyName}.xunit.runner.json file with

{
  "shadowCopy": false
}

In the output directory?

Pilchie commented 7 years ago

Closing as we can't help here without a response. @fubar-coder Please answer @tmat's question above if you're still blocked.

fubar-coder commented 7 years ago

I'll try the suggestion from @tmat

fubar-coder commented 7 years ago

@Pilchie @tmat No, I don't have such a file in the output. Here's an example project: test-xunit.zip

tmat commented 7 years ago

Does it work when you add it?

fubar-coder commented 7 years ago

No, it doesn't work. I added a both a TestXUnit.xunit.runner.json and TestXUnit.dll.xunit.runner.json file to the bin\Debug\net46 folder. The exception is the same.

Pilchie commented 7 years ago

@tmat: Ping?

kzu commented 7 years ago

This is happening to me too. I could get an absolute minimal repro for my scenario (an MSBuild task that uses Roslyn).

WrongDependencies.zip

From the attached readme:

  1. Open the solution
  2. Build solution
  3. Set a breakpoint in UseRoslyn.cs (line 11)
  4. F5

Result: exception thrown:

System.Reflection.ReflectionTypeLoadException occurred
  HResult=0x80131602
  Message=Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
  Source=mscorlib
  StackTrace:
   at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
   at System.Reflection.RuntimeAssembly.get_DefinedTypes()
   at System.Composition.Hosting.ContainerConfiguration.<WithAssemblies>b__0(Assembly a)
   at System.Linq.Enumerable.<SelectManyIterator>d__16`2.MoveNext()
   at System.Composition.TypedParts.TypedPartExportDescriptorProvider..ctor(IEnumerable`1 types, AttributedModelProvider attributeContext)
   at System.Composition.Hosting.ContainerConfiguration.CreateContainer()
   at Microsoft.CodeAnalysis.Host.Mef.MefHostServices.Create(IEnumerable`1 assemblies)
   at Microsoft.CodeAnalysis.Host.Mef.MefHostServices.get_DefaultHost()
   at Microsoft.CodeAnalysis.AdhocWorkspace..ctor()
   at CustomTask.UseRoslyn.Execute() in C:\Delete\WrongDependencies\CustomTask\UseRoslyn.cs:line 11
   at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
   at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__26.MoveNext()

with a LoaderExceptions showing the following Fusion log:

=== Pre-bind state information ===
LOG: DisplayName = System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 (Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/MSBuild/15.0/Bin/
LOG: Initial PrivatePath = NULL
Calling assembly : System.Reflection.Metadata, Version=1.4.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/MSBuild/15.0/Bin/System.Collections.Immutable.DLL.
WRN: Comparing the assembly name resulted in the mismatch: Build Number
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/MSBuild/15.0/Bin/System.Collections.Immutable/System.Collections.Immutable.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/MSBuild/15.0/Bin/System.Collections.Immutable.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2017/Enterprise/MSBuild/15.0/Bin/System.Collections.Immutable/System.Collections.Immutable.EXE.
LOG: Attempting download of new URL file:///C:/Delete/WrongDependencies/CustomTask/bin/Debug/net461/System.Collections.Immutable.DLL.
WRN: Comparing the assembly name resulted in the mismatch: Build Number
LOG: Attempting download of new URL file:///C:/Delete/WrongDependencies/CustomTask/bin/Debug/net461/System.Collections.Immutable/System.Collections.Immutable.DLL.
LOG: Attempting download of new URL file:///C:/Delete/WrongDependencies/CustomTask/bin/Debug/net461/System.Collections.Immutable.EXE.
LOG: Attempting download of new URL file:///C:/Delete/WrongDependencies/CustomTask/bin/Debug/net461/System.Collections.Immutable/System.Collections.Immutable.EXE.

"Fix":

  1. Open $(VsInstallRoot)\MSBuild\15.0\Bin\MSBuild.exe.config
  2. Add the following binding redirect:
        <dependentAssembly>
          <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
          <bindingRedirect oldVersion="1.2.0.0" newVersion="1.2.1.0" />
        </dependentAssembly>
  1. Rebuild project, F5

Result: everything now works as expected.

kzu commented 7 years ago

FWIW, you can see this is happening to others, i.e. https://github.com/AArnott/CodeGeneration.Roslyn/commit/7b268c2384ba05367026a0e49147c5ed49a3bdda

kzu commented 7 years ago

I just hit another one after that: System.IO.FileSystem is exactly in the same situation, with 4.0.1.0 being loaded instead of 4.0.2.0:

The fix in this case is:

        <dependentAssembly>
          <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
          <bindingRedirect oldVersion="4.0.1.0" newVersion="4.0.2.0" />
        </dependentAssembly>
Pilchie commented 7 years ago

@DustinCampbell can you help take a look at this too? Maybe we need an end to end sample of how to use MSBuildWorkspace on a machine with only VS 2017. (Just thinking about the .NET Framework piece here, without the .NET Core complications)

kzu commented 7 years ago

In my case, it's an AdhocWorkspace