Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NuGet adds wrong binding redirects with .NET 4.7.2 #27430

Closed
robertmuehsig opened this issue Sep 19, 2018 · 17 comments
Closed

NuGet adds wrong binding redirects with .NET 4.7.2 #27430

robertmuehsig opened this issue Sep 19, 2018 · 17 comments

Comments

@robertmuehsig
Copy link

This issue was created because of a discussion on twitter @karelz & @joperezr.

We have a pretty large (+100 proj) solution that we are develop for the past 6-7 years with different Visual Studio versions etc.
Last week I was trying to update our solution from .NET Framework 4.5.2 to 4.7.2 and I tried to updated the most important NuGet packages as well. Sadly I ended up with some pretty strange binding redirects in more or less all app.configs in our whole solution.

I could not easily reproduce the exact issue when I created a simple sample, but I was able to cut out one project from our solution, which behaves strange.

Sample Repo: https://github.com/Code-Inside/Samples/tree/master/2018/Net472WrongBindings

The "OneOffixx.Service.Host" project is a pretty old one and it also referenced a nuget.target file in the csproj. I'm not sure why we still have those .target files in place, but this was OK-ish some years ok.

Keep in mind: The project targets .NET Framework 4.5.2 and has the following binding redirect:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="WindowsBase" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Practices.Prism" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

To reproduce the issue I updated the target version to 4.7.2 and clicked the update all package button on the NuGet Client UI.

After the package installations I got this redirect configuration:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="WindowsBase" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Practices.Prism" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
      </dependentAssembly>
      <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>
      <dependentAssembly>
        <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Diagnostics.Tracing" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
      </dependentAssembly>
    </assemblyBinding>
	</runtime>

With this configuration my application won't start because either System.Runtime.dll is missing or System.Net.Http.dll is missing. When I remove those entries it seems fine. Im my real solution there were some other problematic redirects as well and I needed to clean them manually, but I'm not sure what causes this.

I was unable to reproduce the issue with newer projects - maybe it has something todo with the targets file? Sometimes when I update one nuget package I got some very strange binding redirects automatically injected in each web or app.config.

@joperezr
Copy link
Member

Thanks for reporting this, I'm taking a look at your repro now. Is it also possible to get a msbuild.binlog from one of your projects? That would basically help me check who is injecting the binding redirects and why. In order to produce one, just run the following from a developer command prompt:
msbuild yourProject.csproj /t:rebuild /v:m /bl

@joperezr
Copy link
Member

@robertmuehsig which version of VS are you using? We have changed a bunch the way we generate extra binding redirects with our tooling, and I just tried with latest version of VS (15.8.4 at the time of writing this) with your project after targeting 4.7.2 and updating the packages and I can't repro. I don't see the extra binding redirects added anywhere. Could you update your VS and try again?

@robertmuehsig
Copy link
Author

I updated to 15.8.5 and can still reproduce the issue. When should I run the msbuild command? Before or after I updated the nuget package? It seems they are inserted when I update the NuGet packages.

@joperezr
Copy link
Member

can you repro the issue and then push your changes to your repro Repo? I want to see which exact changes are you doing to retarget. I also want to try to rebuild on my side with the exact project as the one you get the redirects with.

@robertmuehsig
Copy link
Author

Checkout this commit. After I updated the target framework to 4.7.2 and updated the OpenXML nuget package I got the System.Runtime as a binding redirect in my web.config.

@xhoogland
Copy link
Contributor

xhoogland commented Sep 26, 2018

Unfortunately experiencing the same issues as described here. It looks to me that, in this case, the problem is caused by a dependency of DocumentFormat.OpenXml on System.Runtime.Serialization.Xml which has one on System.Runtime. They are added indeed in the progress of running the update-package, whether it is via the GUI or CLI.

Bindingredirects are added regardless of having the checkbox 'Generate binding-redirects', or something like that, checked.

@robertmuehsig
Copy link
Author

I'm pretty sure I have seen other packages behave the same way as the DocumentFormat.OpenXml package. The most common binding redirect that is inserted on our solution was the System.Net.Http package.

@joperezr
Copy link
Member

joperezr commented Oct 8, 2018

Who added those redirects? Was it NuGet? Also, I would strongly recommend migrating to the PackageReference model since using packages.config is legacy and prone to errors, specifically when trying to consume netstandard libraries.

@demirag
Copy link

demirag commented Nov 8, 2018

I am having the same issue. After upgrading the projects to .net framework 4.7.2, I started getting the error for exactly same dlls:

System.Runtime.dll and System.Net.Http.dll

The only way currently to solve this problem is to remove binding redirects of those files from app.config or web.config since those are already included in .net 4.7.2. But the annoying part is whenever you update a nuget package those binding will appear over and over again.

Migrating to PackageReference model also does not solve this problem.

I believe this is happening because some nuget packages has wrong nuspecs targeting towards .net 4.7.2 thus install System.Runtime and System.Net.Http nuget packages.

@codekaizen
Copy link

@joperezr

I would strongly recommend migrating to the PackageReference model

PackageReference isn't available for all project types yet. We have this problem frequently on our WPF projects (Install-Package always adds references to an incompatible version of System.Runtime for projects targeting 4.7.2) and we have to manually revert the app.config changes so that the framework implementation is used.

@joperezr
Copy link
Member

PackageReference isn't available for all project types yet.

That is correct, unfortunately not all projects in VS have the automated way of converting from packages.config into PackageReference. That said, you can still do it manually yourself, and it should work fine by taking a look into your packages.config, and for every entry there, adding one in your .csproj like the following:

Entry in packages.config:

<package id="Microsoft.ServiceFabric" version="6.0.232" targetFramework="net461" />

New entry to add manually on your .csproj:

<ItemGroup>
  <PackageReference Include="Microsoft.ServiceFabric" Version="6.0.232" />
</ItemGroup>

Finally just Remove all of the automatic references that where added by the packages.config (they are easy to spot as the HintPath on the reference will point to your NuGet packages folder)

    <Reference Include="Microsoft.ServiceFabric.Internal, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=AMD64">
      <HintPath>..\packages\Microsoft.ServiceFabric.6.0.232\lib\net45\Microsoft.ServiceFabric.Internal.dll</HintPath>
    </Reference>

I know it's not ideal, (and I would suggest adding if possible an issue through VS Feedback) but it is a process that you only have to go through once and it will remove most of the problems around binding redirects and missing assemblies.

@joperezr
Copy link
Member

joperezr commented May 7, 2019

Given that this issue is not really caused by the framework and it is instead a problem with NuGet's legacy way of referencing packages, I'm closing this issue from the repo. Feel free to add more info or reopen if you think otherwise.

@joperezr joperezr closed this as completed May 7, 2019
@iansul
Copy link

iansul commented May 9, 2019

@joperezr, sorry I never saw the actual reason for the incorrect binding redirect, you said

it is instead a problem with NuGet's legacy way of referencing packages

Are you saying moving to PackageReferences solves the issue? Because demirag commented on Nov 8, 2018 that

Migrating to PackageReference model also does not solve this problem.

I'm runnning the same issue after moving from .NET 4.5 to .NET 4.6.2, and doing
Update-Package -Reinstall and would like to know the correct way to solve the issue, hopefully it's not just revert the bindingRedirect.

@joperezr
Copy link
Member

joperezr commented May 9, 2019

The same sympton (assemblies not found at runtime) may have many root causes, one of them is the fact of using packages.config instead of PackageReference, but it is not the only reason, so for your particular scenario, the reason may be different so moving to PackageReference might not be the only thing you need. If you can provide more details of the error you are getting, specifying if it is an error at runtime or compile time, and attaching a binlog would be great to be able to diagnose what is your particular issue. In order to generate a binlog, please run msbuild yourSolution.sln /t:rebuild /bl from a developer command prompt which will generate a msbuild.binlog file.

@iansul
Copy link

iansul commented May 9, 2019

My errors are run-time binding errors, due to incorrect binding redirects, which I think was the start of this thread. I can see that Update-Package -Reinstall with NuGet (output attached) PackageManager.txt, rewrites the assemblyBindingRedirects for various System DLLS, for that project incorrectly. It doesn't seem like it has anything do to with build. Is there a way to get detailed logging from NuGet?

Shown here, the only changes, besides re-targeting the packages to targetFramework="net462" in the packages.config file, is that the app.config, for the project, has had binding redirects updated:
image

As far as I can tell those re-directs are absolutely incorrect. Version 4.1.0.0 refers to either .NET Standard 1.5 or .NET Core 1 System.Runtime Versions, neither of which is being used. The redirects cause binding failures... System.Runtime_binding_failure.log because it directs Fusion (the .NET Assembly loader) to look for version 4.1.0.0 of the DLLs which are not included in the output of the build. The project refers to .NET 4.6.2 so it includes the 4.0.0.0 version of the DLLs.

@joperezr
Copy link
Member

what seems to be happening here, is that you are still using the packages.config model for NuGet references, which is why NuGet is adding the Binding redirects at install time. This logic is faulted in many cases and legacy, and the new way to generate the binding redirects is at build time, and in order to use this, you need to migrate your project to use PackageReference instead. Once you do that, your App.config should have no binding redirects at all, and (if you have autogeneratebindingredirects turned on) our build targets will calculate the right binding redirects that you will need at runtime, and generate these binding redirects in your config file that gets dropped into your bin folder. This logic has way more knowledge about your references and dependencies, so the calculation of those binding redirects will be much better than the one NuGet does in the legacy packages.config world. So in summary, migrating to PackageReference and enable auto binding redirects should fix your issue.

@iansul
Copy link

iansul commented May 14, 2019

OK, that makes sense, thanks!
I will also attempt to move us onto PackageReference, though some of our project types don't support it. I've seen instructions for doing it manually I'm a bit skeptical about the result.

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 3.0 milestone Jan 31, 2020
@dotnet dotnet locked as resolved and limited conversation to collaborators Dec 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants