Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When do I have to use binding redirects?

Project A uses log4net 1.2.13.0, and depends on Library B, which uses log4net 1.2.11.0. If I do Package Manager Console> Add-BindingRedirect, I get a correct binding redirect in app.config:

  <dependentAssembly>
    <assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-1.2.13.0" newVersion="1.2.13.0" />
  </dependentAssembly>

I thought that this one is required in order for the build to complete. But build succeeds without the redirect as well. Here what I see in build log (verbosity set to detailed):

Unified primary reference "log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a". Using this version instead of original version "1.2.11.0" in "C:\Users\vorou\code\ConsoleApplication1\packages\LibraryB.dll" because AutoUnify is 'true'.

What is that AutoUnify all about? Which one is better, i.e. are there any advantages in having an explicit redirect in .config?

Also, as I can remember, in some cases you are required to add binding redirects. Otherwise the app will blow up at runtime. What are these cases and why that AutoUnify magic isn't working for them?


UPD Here's an excerpt from MSDN about AutoUnify:

This parameter is used for building assemblies, such as DLLs, which cannot have a normal App.Config file. When true, the resulting dependency graph is automatically treated as if there were an App.Config file passed in to the AppConfigFile parameter. This virtual App.Config file has a bindingRedirect entry for each conflicting set of assemblies such that the highest version assembly is chosen. A consequence of this is that there will never be a warning about conflicting assemblies because every conflict will have been resolved.

It looks like redirects in .config don't play any role in my case. The problem is Library B can't satisfy it's dependencies, and AutoUnify solves it with that “pretend there are binding redirects” rule.

like image 205
vorou Avatar asked Apr 18 '15 12:04

vorou


People also ask

What do binding redirects do?

Rely on automatic binding redirection This means that if two components reference different versions of the same strong-named assembly, the runtime automatically adds a binding redirection to the newer version of the assembly in the output app configuration (app. config) file.

What is app config?

App. Config is an XML file that is used as a configuration file for your application. In other words, you store inside it any setting that you may want to change without having to change code (and recompiling). It is often used to store connection strings.


1 Answers

Versioning is a big topic, can't do it justice in a single SO post. So break-neck speed:

These kind of shenanigans are necessary when you use multiple Nuget packages and they have a common dependency. Like log4net or NewtonSoft.Json, very common libraries that don't have an installer that put the assembly in the GAC.

Problem is, each Nuget package is very likely to built with a different version of these core support libraries. And such a package is unlikely to get enough updates to keep the current with the latest release, the package author favors the version he tested his code with. So you'll easily end up with one assembly in your build directory that asks for 1.2.11.0 and another that asks for 1.2.13.0

That cannot work. The CLR insists on an exact version match when it loads an assembly. And has to load it from your build directory and can't rely on the GAC to supply them. There can be only one copy of the DLL, inevitably one of the package libraries is going to get the wrong version and your program will crash. Not good, you have a problem you can't solve without a rebuild of the Nuget package.

That's what the binding redirect solves. It only has an affect at runtime, not build time. It tells the CLR, "if it asks for 1.2.11.0 then just load 1.2.13.0 instead. Or more generally with this specific binding redirect: "if it asks for any version less than 1.2.13.0". Problem solved, no crash anymore. Fingers crossed that the package still works with that newer version. They pretty commonly do when only the revision number is different. No hard guarantee however.

Another thing that needs to be decided, this happens at build time, is which specific version of the library should be selected. Do you want 1.2.11.0 or 1.2.13.0? That's what AutoUnify does. Nothing very complicated, it picks the higher version.

like image 142
Hans Passant Avatar answered Sep 17 '22 14:09

Hans Passant