MissingMethodException when referencing Microsoft.

2019-06-21 20:38发布

问题:

I have a "Classic Desktop" .NET project which references Microsoft.Build 15.1 from NuGet and System.IO.Compression/System.IO.Compression.FileSystem from the .NET SDK / GAC.

I'm trying to upgrade this to Microsoft.Build 15.3.

Microsoft.Build 15.3 introduces a dependency on System.IO.Compression 4.1.2.0. The version of System.IO.Compression in the .NET Framework is 4.0.0.0.

If I compile like this, I get a warning about being unable to resolve assembly conflicts, but my code works:

warning MSB3277: Found conflicts between different versions of the same dependent assembly that could not be resolved. These reference conflicts are listed in the build log when log verbosity is set to detailed.

Setting the build log verbosity to Detailed yields this output:

1>  There was a conflict between "System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" and "System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".
1>      "System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" was chosen because it was primary and "System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" was not.
1>      References which depend on "System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" [C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.IO.Compression.dll].
1>          C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.IO.Compression.dll
1>            Project file item includes which caused reference "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.IO.Compression.dll".
1>              System.IO.Compression
1>      References which depend on "System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" [C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\System.IO.Compression.dll].
1>          C:\Temp\CompressionMissingMethod\packages\Microsoft.Build.15.3.409\lib\net46\Microsoft.Build.dll
1>            Project file item includes which caused reference "C:\Temp\CompressionMissingMethod\packages\Microsoft.Build.15.3.409\lib\net46\Microsoft.Build.dll".
1>              Microsoft.Build, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(1988,5): warning MSB3277: Found conflicts between different versions of the same dependent assembly that could not be resolved.  These reference conflicts are listed in the build log when log verbosity is set to detailed.

I can resolve the warning by replacing the SDK/GAC reference to System.IO.Compression with a NuGet reference. As soon as I do this, however, code using ZipFile crashes with a MissingMethodException when the JIT gets to that method.

Unhandled Exception: System.MissingMethodException: Method not found: 'System.IO.Compression.ZipArchive System.IO.Compression.ZipFile.OpenRead(System.String)'. at CompressionMissingMethod.Program.Main(String[] args)

I've put together a very minimal repro case which illustrates this behaviour (check out the branches).

Is there any way to reference both Microsoft.Build 15.3 and System.IO.Compression with no errors, warnings, or exceptions?

回答1:

To fix problem indicated by MSB3277 warning (as well as missing method exception problem) - you need to add binding redirect to your app.config file, so that all bindings are redirected to the last version (4.1.2.0 in this case):

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
      <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

So, install Microsoft.Build 15.3, install System.IO.Compression from nuget (which moves your state to that of MissingMethodException case), then add redirect above and exception will go away and things will work without exceptions or warnings.

Alternative suggested in comments is to update all packages to last versions - this also works because of the same reason - binding redirect. If you update all packages then rebuild - a lot of redirects will be added to your config, including redirect for System.IO.Compression (but to version 4.2.0.0). Note that those redirects will be added not to your app.config but directly to the output YourAppName.exe.config file.