3
votes

Setup

As part of migrating a large VS solution from .Net 4.6 to 4.7.1, I have replaced all packages.config files with "PackageReferences" in each .csproj file and removed the corresponding standard "Reference" tags containing hint paths pointing at the now obsolete "../packages/*" directory. I have also added the <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> and <RestoreProjectStyle>PackageReference</RestoreProjectStyle> to each .csproj file. This .Net 4.7.1 library has various project references to other .Net 4.7.1 libraries and NuGet packages (some of them targeting .NET Standard versions).

Execution

I have a PowerShell script which loads this particular .NET 4.7.1 library through Assembly.LoadFrom("C:\Net471LibraryOutput\Net471Library.dll"), instantiates a class in that assembly through new-object Net471Library.MyClass, and then attempts to execute an async method on that class, but is met with a "MethodNotFoundExcepion" saying that a method defined in a PackageReferenced NugetPackage which references System.Net.Http can't be found.

Observations

My .NET 4.7.1 library references another 4.7.1 project which references System.Net.Http without a specific version, which VS 2017 resolves to version 4.2.0.0 which it found at C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net471\lib\System.Net.Http.dll When I look at the current AppDomain's assemblies after loading this library through reflection, but before executing the command I see my 4.7.1 library's .dll and no System.Net.Http.dll has been loaded. After executing the command I find 2 entries for System.Net.Http have been loaded into the appdomain, each with a distinct version.

  • C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Net.Http.dll (version 4.0.0.0)
  • C:\Net471LibraryOutput\System.Net.Http.dll (version 4.2.0.0)

If I hide System.Net.Http 4.2.0.0 from VS and rebuild, Net471Library output no longer contains System.Net.Http.dll, and if I repeat those steps without that .dll present, the method executes successfully (no "MethodNotFoundException" on the referenced NuGet package method). If I allow VS to find System.Net.Http 4.2.0.0, even if I set all referenced projects to use 4.0.0.0 specifically (though I can't adjust the PackageReferenced NuGet packages), version 4.2.0.0 still gets placed in the output and I receive the same error. If I try to add a reference to System.Net.Http directly to the library to try to force the output, I get build error CS0433 "The type 'HttpResponseMessage' exists in both 'System.Net.Http, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' and 'System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'"

I have made several attempts to reproduce the issue in a simplified solution with fewer dependencies to narrow down the issue but have been unsuccessful so far.

2
Found an issue posted here: github.com/dotnet/corefx/issues/25773Nathan Turnbow

2 Answers

4
votes

The reason why you are seeing this is that most likely you are using Visual Studio 15.5.* to build your app, which is missing a recent fix we added for projects targetting 4.7.1 in order to automatically add binding redirects to a few list of facades. That change has been added now and will be shipped in VS 15.6 Preview 3 and later versions. In order to workaround the issue for now, is to manually add the binding redirects you need which in this case is:

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  <dependentAssembly>
    <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
  </dependentAssembly>
</assemblyBinding>

Can you check if adding that fixes your issue? If you want more info on the fix we made, you can take a look at this github pull request: https://github.com/dotnet/corefx/pull/25786

1
votes

Sorry, this might be better as a comment, but I dont have the reputation yet to comment.

Nathan Turnbow, for a binding redirect to apply, it must be in the app.config file of the application loading these dlls. This usually means in your app.config for your .exe, that will be automatically renamed to ProgramName.exe.config, or in your web.config.

In your case I think it's different because it's powershell that loads your dlls. I found this that might help:

Powershell config assembly redirect

PowerShell App.Config (Not sure binding redirects in this case)

Btw, to debug these kind of issues, you can use fuslogvw to see clear logs of what is loaded and why.

I hope this helps,