Sdk: Binding redirects are not generated automatically even with AutoGenerateBindingRedirects

Created on 16 Jun 2017  Â·  19Comments  Â·  Source: dotnet/sdk

There are two issues here:

  • First the <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> is not recognized. The warning message is wrong:
`<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net462</TargetFramework>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
    <PackageReference Include="WindowsAzure.Storage" Version="7.2.1" />
  </ItemGroup>
</Project>`
Produces a warning message saying: 

 `1>Consider app.config remapping of assembly "Newtonsoft.Json, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed" from Version "6.0.0.0" [] to Version "9.0.0.0" [C:\Users\me\.nuget\packages\newtonsoft.json\9.0.1\lib\net45\Newtonsoft.Json.dll] to solve conflict and get rid of warning.

1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(1964,5): warning MSB3276: Found conflicts between different versions of the same dependent assembly. Please set the "AutoGenerateBindingRedirects" property to true in the project file. For more information, see http://go.microsoft.com/fwlink/?LinkId=294190.`

The information in the link says I should enable `AutoGenerateBindingRedirects`, but indeed `<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>`  is activated.
  • Second: No redirects are created. The assemblies try to access the same wrong version described in the error message.

It looks like the <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> is somehow overlooked.

Most helpful comment

@nguerrera Yes, after my last message I was trying new solutions and the one proposed in here worked for me. So, none of the other solutions had any effect. The only thing that created the redirects was adding the target:

<Target Name="ForceGenerationOfBindingRedirects"
          AfterTargets="ResolveAssemblyReferences"
          BeforeTargets="GenerateBindingRedirects"
          Condition="'$(AutoGenerateBindingRedirects)' == 'true'">
    <PropertyGroup>
      <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
    </PropertyGroup>
  </Target>

Without that the error will happen whenever I run the build in Windows. It happens both if the conflict is in a dependent dll or in the .exe (no difference at all).

All 19 comments

Try adding an app.config file to your project. I think the issue is that without that, it won't generate binding redirects. Also, projects using Microsoft.NET.Sdk should have the auto generate property enabled by default, so you probably don't need that in your project file.

@dsplaisted
Thank you for your answer.
I tried with the app.config file in the first place, in a project with the old csproj format. Again ignored.

I used binding redirects in the past and this always worked fine. No clue what is wrong now.

Try adding app.config to a project in the new format.

Sent from my Windows 10 phone

From: Jose
Sent: Monday, June 19, 2017 3:47 AM
To: dotnet/sdk
Cc: Daniel Plaisted; Mention
Subject: Re: [dotnet/sdk] Binding redirects are not generated automaticallyeven with AutoGenerateBindingRedirects (#1351)

@dsplaisted
Thank you for your answer.
I tried with the app.config file in the first place, in a project with the old csproj format. Again ignored.
I used binding redirects in the past and this always worked fine. No clue what is wrong now.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

@dsplaisted The app.config is not required to exist in source, it will still be generated.

@Jose-CF I just tried with the exact project in the bug description and it created bin\Debug\net462*.exe.config with:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Can you tell me the VS version you have as indicated in Help -> About Microsoft Visual Studio?

@nguerrera Over here not working. Already when building in the build messages msbuild complains about the broken dependency and suggest to add the binding redirect. Ironically the binding redirect is already there!
Latest VS 2017 community, updated in the last 24 hours.

Notice however, the thing builds, and if I try to run it with mono, it will run flawlessly.

@Jose-CF on https://github.com/Microsoft/msbuild/issues/1310#issuecomment-309622789 you indicate that the workaround for getting binding redirects for libraries worked for you. Is that the same issue as this? Note that the project you put in the description of this bug has output type winexe so it works without a workaround. I am unable to repro the issue on any version of VS 2017 with that project.

@nguerrera Yes, after my last message I was trying new solutions and the one proposed in here worked for me. So, none of the other solutions had any effect. The only thing that created the redirects was adding the target:

<Target Name="ForceGenerationOfBindingRedirects"
          AfterTargets="ResolveAssemblyReferences"
          BeforeTargets="GenerateBindingRedirects"
          Condition="'$(AutoGenerateBindingRedirects)' == 'true'">
    <PropertyGroup>
      <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
    </PropertyGroup>
  </Target>

Without that the error will happen whenever I run the build in Windows. It happens both if the conflict is in a dependent dll or in the .exe (no difference at all).

That workaround is only be needed when the output type is not exe or winexe. GenerateBindingRedirectsOutputType would already be set to true for WinExe (as in your example above) here:
https://github.com/Microsoft/msbuild/blob/dc1f683b20dc17266c4e4b47b4b03dd7a9acef81/src/Tasks/Microsoft.Common.CurrentVersion.targets#L324.

Were you actually seeing the issue with the project that you put here in the bug description or just another project that outputs a dll and not an exe?

The redirects were not created either for libraries or for .exe.
<OutputType>Exe</OutputType>
Does not make any difference over here.
I understand it _should_ work without the target. But indeed it did not. Either library or exe.
Using msbuild Microsoft (R) Build Engine version 15.2.0.0

So the exact project in this bug's description doesn't work without a target for you?

Exactly.
It only works if I set
<Target Name="ForceGenerationOfBindingRedirects" AfterTargets="ResolveAssemblyReferences" BeforeTargets="GenerateBindingRedirects" Condition="'$(AutoGenerateBindingRedirects)' == 'true'"> <PropertyGroup> <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType> </PropertyGroup> </Target>

I have a similar issue, with binding redirect not being added for a PackageReference. not sure if you want me to detail it here or create a seperate issue - but here goes:

I have a web application <Project Sdk="Microsoft.NET.Sdk.Web"> with a project reference to a library application: <Project Sdk="Microsoft.NET.Sdk"> The library project has a PackageReference to a nuget package that has a dependency constraint Microsoft.Extensions.DependencyInject.Abstractions >= 1.0.0. I have then upgraded this dependency to version 1.0.2 (within the library project):
image

I have fully cleaned (deleted bin folder) and rebuilt the web application. In the bin folder is: Microsoft.Extensions.DependencyInject.Abstractions version 1.0.2 as expected. When my application runs here is the fusion log from the exception:

=== Pre-bind state information ===
LOG: DisplayName = Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
 (Fully-specified)
LOG: Appbase = file:///C:/Users/darrell.tunnell/Source/Repos/gluon/src/Gluon.WebApplication/bin/Debug/net46/
LOG: Initial PrivatePath = NULL
Calling assembly : Hangfire.AspNetCore, Version=1.6.12.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Users\darrell.tunnell\Source\Repos\gluon\src\Gluon.WebApplication\bin\Debug\net46\Gluon.WebApplication.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
LOG: Attempting download of new URL file:///C:/Users/darrell.tunnell/Source/Repos/gluon/src/Gluon.WebApplication/bin/Debug/net46/Microsoft.Extensions.DependencyInjection.Abstractions.DLL.
WRN: Comparing the assembly name resulted in the mismatch: Build Number
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

Checking the binding redirects in the generated config xml file - there has been no assembly binding generated for Microsoft.Extensions.DependencyInjection.Abstractions.

Here is my VS version:

image

Hi,
I understand that my solution for this problem is rather weird, and there is a better options, but I had nothing else to do :(
I have net standard 1.6 library, and unit test that must be run on windows, so it is test project on .NET 4.7
I referenced my library from test project, it builds fine, but it did not run. It started complaining on missing assemblies, on version mismatch etc. Over the time I accumulated about 40 references and binding redirects on previous version (ns1.4 and .NET 4.6), so after upgrade I was horrified with amount of work to do in order to fix that. Auto generate bindidngs flag did not have any effect. So I ended up with next solution: I run my test, catch exception and append binding redirect to app.config, or report missing reference and manually add them from nuget (repeat until satisfied).
That took about 15 minutes to complete. It is rather dodgy solution, but solved the issue.
It also somehow produced multiple redirects for different versions, which is a bit weird, so check final app.config for duplicates

using System;
using System.Reflection;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.IO;
using System.Collections.Generic;
using System.Net.Http;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Tests
{
[TestClass]
public class BindingRedirect
{
[TestMethod]
public void BindingRedirect_Manual()
{
var tmp = context;

        Func<string,string> formatRedirect = (message) =>
        {
            var match = Regex.Match(message, "'([a-zA-Z._0-9]*),.*=([a-zA-Z-0-9]*)'");

            var assembly = Assembly.Load(match.Groups[1].Value);
            var name = assembly.GetName();
            var publicKey = string.Join("", name.GetPublicKeyToken().Select(b => b.ToString("X2")));

            var parts = new[] {
                    "<dependentAssembly>",
                    $"\t<assemblyIdentity name=\"{name.Name}\" publicKeyToken=\"{publicKey}\" culture=\"neutral\" />",
                    $"\t<bindingRedirect oldVersion=\"0.0.0.0-{name.Version}\" newVersion=\"{name.Version}\"/>",
                    "</dependentAssembly>"
                };

            var redirect = string.Join(Environment.NewLine, parts);

            var configPath = @"<PATH_TO_APP_CONFIG>";
            var configLines = File.ReadAllLines(configPath);
            var newLines = configLines.Select(l =>
            {
                if (l.Contains("</assemblyBinding>"))
                {
                    return parts.Union(new[] { l });
                }

                return new List<string>() { l };
            }).SelectMany(l => l);

            File.WriteAllLines(configPath, newLines);

            return redirect;
        };


        Action<Exception> dispatchException = null;
        dispatchException = (ex) =>
        {
            switch(ex)
            {
                case FileNotFoundException fnfe:
                    {
                        var name = fnfe.FileName.Split(new[] { ',' }).First();
                        Clipboard.SetText(name);
                        Assert.Fail($"No reference: {name}");
                    }
                    break;
                case ReflectionTypeLoadException rtle:
                    {
                        var messages = rtle.LoaderExceptions.GroupBy(e => e.Message);

                        var redirects = messages.Select(group => formatRedirect(group.Key));

                        var allRedirects = string.Join(Environment.NewLine, redirects);

                        Clipboard.SetText(allRedirects + Environment.NewLine);

                        Assert.Inconclusive(allRedirects);
                    }
                    break;
                case FileLoadException fle:
                    {
                        var redirect = formatRedirect(fle.Message);
                        Clipboard.SetText(redirect + Environment.NewLine);
                        Assert.Inconclusive(redirect);
                    }
                    break;
                case AggregateException ae:
                    {
                        dispatchException(ae.InnerException);
                    }
                    break;
                default:
                    Assert.Fail(ex.ToString());
                    break;
            }
        };

        try
        {
            var assembly = Assembly.Load("<ASSEMBLY_NAME>");
            foreach(var t in assembly.GetTypes())
            {
                if( t.IsClass && !t.IsGenericTypeDefinition && !t.IsSealed )
                {
                    var ctor = t.GetConstructors().SingleOrDefault(c => !c.GetParameters().Any());
                    if( ctor != null)
                    {
                        var instance = Activator.CreateInstance(t);
                        if (instance == null)
                            Assert.Fail("");
                    }
                }
            }

            // DO SOMETHING ELSE WITH CLASSES
        }
        catch (Exception ex)
        {
            dispatchException(ex);
        }
    }
}

}

I have the same issue with library types. Since this issue looks like it only concerns itself with EXE projects, I've created a new issue here: https://github.com/dotnet/sdk/issues/1595

Same issue here with OutputType Exe. My workaround is to switch the project to Class Library, generate the redirects, and then switch it to Exe again.

Everyone once in a while I find that my binding redirects are not appearing in the .exe.config file. The solution is to delete the 'obj' folder. Then it works again.

That workaround is only be needed when the output type is not exe or winexe. GenerateBindingRedirectsOutputType would already be set to true for WinExe (as in your example above) here:
https://github.com/Microsoft/msbuild/blob/dc1f683b20dc17266c4e4b47b4b03dd7a9acef81/src/Tasks/Microsoft.Common.CurrentVersion.targets#L324.

Were you actually seeing the issue with the project that you put here in the bug description or just another project that outputs a dll and not an exe?

I tried to use the new type with nunit/Specflow Test and it is not generated.

I had this problem and will add my own experience. First off, I ended up turning on <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType for all projects, both libraries and executables. I don't know why this is not the default as this fixed dozens of projects by itself!

I still had a project that generated this mysterious error, even though it was definitely generating the *.dll.config file with all of the correct bindingRedirects. In my case, the problem was caused by a PackageReference that transitively pulls in Microsoft.Bcl.Build. This invisibly changed properties and added targets to the build. Once I turned up the build log verbosity to "Detailed" I found this:

1>Property reassignment: $(AutoUnifyAssemblyReferences)="false" (previous value: "true") at C:\Users\tomk\.nuget\packages\microsoft.bcl.build\1.0.21\build\Microsoft.Bcl.Build.targets (22,5)

Then later, while building target ResolveAssemblyReferences I confirmed:

1>    AutoUnify:
1>        False

.. right before the string of errors.

I have no idea what this property is for, because the bindingRedirects were still created, so whether it liked it or not, the assembly references were unified anyway. I was able to fix the error by adding to my project file:

  <Target Name="ForceAutoUnify"
          BeforeTargets="ResolveAssemblyReferences"
          Condition="'$(AutoGenerateBindingRedirects)' == 'true'">
    <PropertyGroup>
      <AutoUnifyAssemblyReferences>true</AutoUnifyAssemblyReferences>
    </PropertyGroup>
  </Target>

Hopefully this will save time for others, as I was struggling with this for quite a while.

@tomkludy The Microsoft.Bcl.Build package causes problems. We created it way back when to help with things like generating binding redirects, but now that we've mostly fixed them in the product it interferes with things. If you can upgrade to a newer package that doesn't include it as a dependency that should help. If you can't do that, then add the following to your project:

<ItemGroup>
    <PackageReference Include="Microsoft.Bcl.Build" Version="1.0.21" ExcludeAssets="All" />
</ItemGroup>

That should prevent anything from the package from being used.

Also, I highly recommend checking out MSBuild binary logs and the viewer available at https://msbuildlog.com/ instead of trying to dig through verbose text log files.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

srikanthramamurthy picture srikanthramamurthy  Â·  88Comments

NinoFloris picture NinoFloris  Â·  99Comments

ghost picture ghost  Â·  210Comments

dasMulli picture dasMulli  Â·  138Comments

danmosemsft picture danmosemsft  Â·  137Comments