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

Binding redirect in multi-target class library. #20584

Closed
jarenduan opened this issue Mar 12, 2017 · 11 comments
Closed

Binding redirect in multi-target class library. #20584

jarenduan opened this issue Mar 12, 2017 · 11 comments
Labels
area-Meta question Answer questions and provide assistance, not an issue with source code or documentation.
Milestone

Comments

@jarenduan
Copy link
Contributor

How do i redirect the assembly binding in a multi-target class library, such as:

<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.5.10.0" newVersion="2.5.10.0" />

That can be done by app.config in traditional .Net class library. But what about a multi-target class library?

BTW, this issue comes from referencing Microsoft.Bcl.Async when I try to multi-target net40 and netstandard1.4:

<TargetFrameworks>net40;netstandard1.4</TargetFrameworks>

<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
    <PackageReference Include="Microsoft.Bcl.Async">
      <Version>1.0.168</Version>
    </PackageReference>
  </ItemGroup>

And VS2017 gave the warning:

The primary reference "C:\Users\jaren.nuget\packages\microsoft.bcl.async\1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll" could not be resolved because it has an indirect dependency on the framework assembly "System.Runtime, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" which could not be resolved in the currently targeted framework. ".NETFramework,Version=v4.0". To resolve this problem, either remove the reference "C:\Users\jaren.nuget\packages\microsoft.bcl.async\1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll" or retarget your application to a framework version which contains "System.Runtime, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".

According to Microsoft.Bcl.Async FAQ, it seems like binding redirecting is needed.

@jarenduan
Copy link
Contributor Author

I found this saying that binding redirection is gone for it just gives warnings.

But in my case above, THIS IS NOT JUST WARNING!. It can't bind the right DLL, so that there is not "async and await" in net40, so it won't compile!.

@karelz
Copy link
Member

karelz commented Mar 14, 2017

@ericstj @terrajobst any advice?

@ericstj
Copy link
Member

ericstj commented Mar 14, 2017

Those old packages were never intended to work with the new nuget. BCL.Build used a powershell script to install its targets which is no longer supported, it then relied on nuget installing reference items with hintpaths to find the references to redirect, which no longer happens. There's some hacking you could do to make this work but I think manually defining the redirects might be easier. Microsoft.BCL.* packages could consider an update to better work with the new nuget, but most of these are obsolete now that .net 4.0 is out of support.

@jarenduan if you want configuration specific redirects, just create a file named something like app.net40.config, then set the AppConfig property to point to that only when targeting net40, for example:

    <AppConfig Condition="'$(TargetFramework)' == 'net40'">app.net40.config</AppConfig>

When I did this with the following content of the app.net40.config it worked for me:

<?xml version ="1.0"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.IO" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

@jarenduan
Copy link
Contributor Author

jarenduan commented Mar 17, 2017

@ericstj Thanks for the analysis and suggestion, I believe you are right. However, I did the app.net40.config thing as you said, and still got the errors.

When it worked for you, is there any "async/await" code in your project? If I compile an empty multi-target project, it will pass the compilation with a few warnings, but it will fail if I write some "async/await" codes.

I am also considering dropping the net40 support, and suggest my users update to net45 or even higher. But only trouble is net40 supports XP, and net45 requires Win7. So net45 is not a perfect upgrade for net40.

@karelz
Copy link
Member

karelz commented Mar 17, 2017

@jarenduan can you paste the code you have to add to empty project to get it failing? The "line" which makes it from OK to broken. That would help us reproduce inhouse.

@jarenduan
Copy link
Contributor Author

jarenduan commented Mar 17, 2017

@ericstj like this:

using System;
using System.Threading.Tasks;

namespace AsyncForNet40 {
    public class Class1 {
        public static async Task Run(Action action) {
            await Task.Factory.StartNew(action);
        }
    }
}

The csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>net40;netstandard1.4</TargetFrameworks>
    <AppConfig Condition="'$(TargetFramework)' == 'net40'">App.net40.config</AppConfig>
  </PropertyGroup>
  
  <ItemGroup Condition=" '$(TargetFramework)' == 'net40' ">
    <PackageReference Include="Microsoft.Bcl.Async" Version="1.0.168" />
    <Reference Include="System" />
    <Reference Include="Microsoft.CSharp" />
  </ItemGroup>
</Project>

The app.net40.config is same as you posted. And in output window:

1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(1964,5): warning MSB3268: The primary reference "C:\Users\jaren.nuget\packages\microsoft.bcl.async\1.0.168\lib\net40\Microsoft.Threading.Tasks.dll" could not be resolved because it has an indirect dependency on the framework assembly "System.Threading.Tasks, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" which could not be resolved in the currently targeted framework. ".NETFramework,Version=v4.0". To resolve this problem, either remove the reference "C:\Users\jaren.nuget\packages\microsoft.bcl.async\1.0.168\lib\net40\Microsoft.Threading.Tasks.dll" or retarget your application to a framework version which contains "System.Threading.Tasks, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(1964,5): warning MSB3268: The primary reference "C:\Users\jaren.nuget\packages\microsoft.bcl.async\1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll" could not be resolved because it has an indirect dependency on the framework assembly "System.Threading.Tasks, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" which could not be resolved in the currently targeted framework. ".NETFramework,Version=v4.0". To resolve this problem, either remove the reference "C:\Users\jaren.nuget\packages\microsoft.bcl.async\1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll" or retarget your application to a framework version which contains "System.Threading.Tasks, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(1964,5): warning MSB3268: The primary reference "C:\Users\jaren.nuget\packages\microsoft.bcl.async\1.0.168\lib\net40\Microsoft.Threading.Tasks.dll" could not be resolved because it has an indirect dependency on the framework assembly "System.Runtime, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" which could not be resolved in the currently targeted framework. ".NETFramework,Version=v4.0". To resolve this problem, either remove the reference "C:\Users\jaren.nuget\packages\microsoft.bcl.async\1.0.168\lib\net40\Microsoft.Threading.Tasks.dll" or retarget your application to a framework version which contains "System.Runtime, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(1964,5): warning MSB3268: The primary reference "C:\Users\jaren.nuget\packages\microsoft.bcl.async\1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll" could not be resolved because it has an indirect dependency on the framework assembly "System.Runtime, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" which could not be resolved in the currently targeted framework. ".NETFramework,Version=v4.0". To resolve this problem, either remove the reference "C:\Users\jaren.nuget\packages\microsoft.bcl.async\1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll" or retarget your application to a framework version which contains "System.Runtime, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
1>Class1.cs(7,13,7,48): error CS1061: 'Task' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'Task' could be found (are you missing a using directive or an assembly reference?)
1>Done building project "AsyncForNet40.csproj" -- FAILED.

Failed.

@ericstj
Copy link
Member

ericstj commented Mar 17, 2017

If you're getting those warnings it means the binding redirects are not correct. Let me share the exact project that worked for me.

@ericstj
Copy link
Member

ericstj commented Mar 17, 2017

It looks like you also need to set

<AutoUnifyAssemblyReferences  Condition="'$(TargetFramework)' == 'net40'">false</AutoUnifyAssemblyReferences>

Previously this was set by the BCL.Build targets which aren't being imported as I mentioned above.

With those two settings I can successfully build your sample. Gist is here:
https://gist.github.com/ericstj/7df5e4b09b6c706758c3812e48a46a59

@jarenduan
Copy link
Contributor Author

@ericstj, thank you for your generous help. It works!

I've learned from your solution that remember to examine the building target of the old packages when there're something wrong.

Thanks to everyone got involved. You guys did a very good job.

@karelz
Copy link
Member

karelz commented Mar 18, 2017

Thanks @ericstj for guidance! I didn't follow all technical details - is there anything we could/should do in product (e.g. tooling) or in docs to make the experience better?
Or is it an exceptional one off problem?

@jarenduan
Copy link
Contributor Author

@karelz, well, some old packages rely on install.ps1/init.ps1 to do some stuffs, and according to my understanding, these scripts are not supported in the new version of Nuget. I guess we should consider including these changes in the nuget docs.

And speaking of tooling, we now have nuget/dotnet/msbuild all in vs2017. I believe they are not exactly the same as each other. It seems like there is a little bit confusion about when to use which. It'd best provide a unified tooling experience.

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 2.0.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-Meta question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
None yet
Development

No branches or pull requests

4 participants