MSBuild with target netfx48 temp files present fails with Missing Method.

See original GitHub issue

Issue Description

Using a roslyn CodeAnalysis project running on net48 attempting to load a project also targetting net48 will fail to load dependencies caused by a missing method Method not found: 'System.ReadOnlySpan`1<Char> Microsoft.IO.Path.GetFileName(System.ReadOnlySpan`1<Char>)' if the target project has already been compiled and has bin/obj directories present.

Steps to Reproduce

CodeAnalysisApp2.zip Repro is attached. To use

  1. unzip and open the CodeAnalysisApp2.sln file then run it. It should load the console app solution and correctly run through to the console readline without displaying any problems.
  2. open the ConsoleApp2.sln and compile or run it
  3. reopen the CodeAnalysisApp2.sln and run it again, you should get an error:
Using MSBuild at 'C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin' to load projects.
Loading solution '..\..\..\..\ConsoleApp2.sln'
Evaluate        0:00.2464048    ConsoleApp2.csproj
Msbuild failed when processing the file 'D:\Programming\csharp10\CodeAnalysisApp2\ConsoleApp2\ConsoleApp2.csproj' with message: Method not found: 'System.ReadOnlySpan`1<Char> Microsoft.IO.Path.GetFileName(System.ReadOnlySpan`1<Char>)'.
Finished loading solution '..\..\..\..\ConsoleApp2.sln'

Versions & Configurations

Latest VS 17.3 update, this worked on 17.2. MSBuild version 17.3.0+f67e3d35e for .NET Framework 17.3.0.37102

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:7
  • Comments:13 (8 by maintainers)

github_iconTop GitHub Comments

10reactions
rainersigwaldcommented, Aug 25, 2022

Thanks for the repro project, that plus another nice repo from a Microsoft-internal person really helped me understand what’s going on here, which is this:

  1. Roslyn 4.2 has (transitive) dependencies on System.Memory 4.0.1.1 (from package version 4.5.4).
  2. MSBuild 17.2 has (transitive) dependencies on System.Memory 4.0.1.1 (from package version 4.5.4).
  3. MSBuild 17.3 has dependencies on System.Memory 4.0.1.2 (from package version 4.5.5).
  4. Since those versions differ, the strong names of the assemblies differ, so the .NET Framework is happy to load them side by side (this would be different on .NET 6).
  5. At runtime, Locator correctly hooks up its assembly resolve events.
  6. Then Roslyn stuff or the app itself call some method that causes System.Memory 4.0.1.1 to be loaded.
  7. Then MSBuild is called and resolved through Locator’s event handlers.
  8. Then MSBuild tries to call System.Memory 4.0.1.2, which is located and loaded by Locator.
  9. Everything is great! The assemblies are side-by-side but don’t try to interchange types so everything is happy.
  10. Then MSBuild tries to call this method:

https://github.com/dotnet/msbuild/blob/92e0776509a23ed2c1e24bf906a92f045899b885/src/Shared/FileMatcher.cs#L1653-L1663

which compiles down to this IL for our net472 target:

    IL_0000: ldarg.0
    IL_0001: call valuetype [System.Memory]System.ReadOnlySpan`1<char> [System.Memory]System.MemoryExtensions::AsSpan(string)
    IL_0006: call valuetype [System.Memory]System.ReadOnlySpan`1<char> [Microsoft.IO.Redist]Microsoft.IO.Path::GetFileName(valuetype [System.Memory]System.ReadOnlySpan`1<char>)
    IL_000b: ldarg.1
    IL_000c: call bool Microsoft.Build.Shared.FileMatcher::IsMatch(valuetype [System.Memory]System.ReadOnlySpan`1<char>, string)
    IL_0011: ret
  1. This throws System.MissingMethodException: 'Method not found: 'System.ReadOnlySpan`1<Char> Microsoft.IO.Path.GetFileName(System.ReadOnlySpan`1<Char>)'.'
  2. But why? We have a System.Memory of both versions loaded!
  3. Microsoft.IO.Redist.dll depends on System.Memory 4.0.1.1 (it is unchanged but System.Memory has a new version)
  4. So its return type is really [System.Memory 4.0.1.1] System.ReadOnlySpan`1<char>, but the type we need in Microsoft.Build is a [System.Memory 4.0.1.2] System.ReadOnlySpan`1<char> (because that was the winning version in our build).
  5. That’s a mismatch, so the MissingMethodException is thrown: no method found matching that (version of) that type in its signature.
  6. This doesn’t fail in normal MSBuild.exe operation, because we have binding redirects in place that ensure that all System.Memory types are 4.0.1.2:

https://github.com/dotnet/msbuild/blob/92e0776509a23ed2c1e24bf906a92f045899b885/src/MSBuild/app.amd64.config#L85-L86

  1. In the client application, there is no such binding redirect, because it’s compiled against the .2 versions of everything that don’t need one.

Tactically, there are two fixes that can be applied:

  1. Update the application’s reference to the System.Memory to version 4.5.5 and binding redirect to it a. This may require adding the reference explicitly; it was likely transitive before b. Updating MSBuild references to 17.3 will do this automatically since that package depends on 4.5.5. c. You probably don’t need to do binding redirects manually because they should be automatic
  2. Remove System.Memory.dll from the application directory a. This causes Locator to find the System.Memory that lives in MSBuild, which will be the correct version for MSBuild. b. If that version is the only version that can be loaded, the .NET Framework (essentially) binding-redirects all references to that version, so everything sees 4.0.1.2 and is consistent c. This can be nontrivial since it’s coming to the app’s output folder as a transitive reference. d. This also requires that MSBuildLocator be called before using any System.Memory types, which is stricter than was required before.
0reactions
Forgindcommented, Oct 21, 2022

Were either of rainersigwald’s mitigations helpful: https://github.com/dotnet/msbuild/issues/7873#issuecomment-1227332842 ?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Daniel Cazzulino's Post - dotnet/msbuild
TIL: Missing Method exceptions during test runs (i.e. in #nugetizer) can be fixed by bumping to #msbuild 17.3.1: MSBuild with target netfx48 temp...
Read more >
System.Memory.dll issue - Rhino Developer - McNeel Forum
MSBuild with target netfx48 temp files present fails with Missing Method. opened 10:12PM - 10 Aug 22 UTC. Wraith2. bug Documentation Breaking ...
Read more >
MSBuild fails due to missing files - that I actually want to ...
I'm attempting to set up a Continuous Integration process for a legacy VB.Net ASP.Net Forms application, using Visual Studio 2015 and an on ......
Read more >
Fix intermittent build failures
Learn how to diagnose and fix race conditions in your MSBuild parallel builds.
Read more >
MSB6003: The specified task executable ...
This error indicates that an executable that was part of the build process could not be executed. There is usually an additional error...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found