dotnet / standard

This repo is building the .NET Standard
3.06k stars 427 forks source link

Issues with .NET Standard 2.0 with .NET Framework & NuGet #481

Closed terrajobst closed 5 years ago

terrajobst commented 7 years ago

Summary

We've designed .NET Standard & our tooling so that projects targeting .NET Framework 4.6.1 can consume NuGet packages & projects targeting .NET Standard 2.0 or earlier. Unfortunately, we've seen a few issues around that scenario. The purpose of this document is to summarize the issues, outline our plan on addressing them, and providing workarounds you can deploy with today's state of our tooling.

Symptoms and root cause

The primary symptom is that applications crash with a FileLoadException or a FileNotFoundException. Another symptom is warnings at build time regarding assembly versions. This is due to one or both of the following issues:

  1. Missing binding redirects
  2. Missing binaries that come from indirect NuGet packages

Missing binding redirects

.NET Standard 1.x was based around contracts. Many of these contracts shipped with .NET Framework 4.5 and later. However, different versions of .NET Framework picked up different versions of these contracts, as by-design of contract versioning. As a side effect of marking .NET Framework 4.6.1 as implementing .NET Standard 2.0, some projects will now start picking up binaries built for .NET Standard 1.5 and 1.6 (as opposed to previously where .NET Framework 4.6.1 was considered as implementing .NET Standard 1.4). This results in mismatches of the assembly versions between what was shipped in .NET Framework and what was part of .NET Standard 1.5/1.6.

This can be addressed by binding redirects. As writing them by hand sucks, we added an Automatic Binding Redirect Generation feature in .NET Framework 4.5.1. This feature is opt-in. Unfortunately, it's not enabled based on target framework, but by which target framework was selected when the project was created (as the feature is turned on via an MSBuild property that is conditionally emitted by the template). In practice, this means it's mostly off if you often upgrade existing projects, rather than creating new ones.

Missing binaries

There are two primary flavors of NuGet: packages.config and PackageReference.

The default for .NET Framework projects is packages.config. This ensures more compatibility because PackageReference doesn't support all the features that packages.config did, for example, PowerShell install scripts and content.

The only supported mode for SDK-style projects (.NET Core/.NET Standard) is PackageReference. This means that a .NET Framework project referencing a .NET Standard project ends up crossing the streams between two different NuGet models. When the .NET Standard project references NuGet packages that the .NET Framework project doesn't reference, the application ends up missing all binaries coming from those packages.

Why has this worked before? Because withpackages.config, all dependencies are copied to each project's output folder. MSBuild copies them up from there. With PackageReference, we don't copy the binaries because it relies on the consuming project to see its dependencies and extract the proper asset itself. This allows the consuming project to pick up the right assets for packages that use bait & switch (which many of the .NET packages must do).

Plan

The plan is to address these issues moving forward as follows:

  1. Converge on PackageReference for all project types, including .NET Framework. The short-term plan for (1) is to start blocking project-to-project references in Visual Studio 15.4 that will end up crossing the streams between packages.config and PackageReference. This block is UI only; you can still edit the reference by editing the project by hand. The error message will instruct you to switch the .NET Framework project to PackageReference if you want to reference a .NET Standard project. Referencing .NET Standard binaries or NuGet packages will not require this, it's only about project-to-project references. In later releases, we plan on providing a converter. The challenge is that packages.config has features we can't offer for PackagReference across the board, in particular PowerShell install scripts and content. We'll need good guidance and mitigations, if applicable.

  2. Ensure binding redirects are on by default. Short term, this means we need to fix our target files to make sure we turn on automatic binding redirect generation. However, binding redirects don't work well in all scenarios, when there is no application project (like unit tests or add-ins). We need to work on a plan to bring the regular “higher wins” binding policy without binding redirects. This needs a proposal and proper vetting, but it seems we've reached the point where this is necessary.

Workarounds

Regular .NET Framework projects

  1. Enable automatic binding redirects in the root .NET Framework application.
  2. Make sure your root application project doesn't use packages.config but uses PackageReference for NuGet packages
    • If you currently don't have packages.config, simply add <RestoreProjectStyle>PackageReference</RestoreProjectStyle> to your project file
    • If you currently do have a packages.config, convert the contents to packages references in the project file. The syntax is like this:
      • <PackageReference Include="package-id" Version="package-version" />

ASP.NET web applications and web sites

  1. Web applications and web sites don't support automatic binding redirect generation. In order to resolve binding conflicts, you need to double click the warning in the error list and Visual Studio will add them to your web.config file.
  2. In web application projects, you should enable PackageReference like mentioned above. In web sites, you cannot use PackageReference as there is no project file. In that case, you need to install all NuGet packages into your web site that any of the direct or indirect project references depend on.

Unit tests projects

By default, binding redirects aren't added to class library projects. This is problematic for unit testing projects as they are essentially like apps. So in addition to what's outlined in automatic binding redirects you also need to specify GenerateBindingRedirectsOutputType:

<PropertyGroup>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
KevinRansom commented 7 years ago

@forki, @terrajobst, @isaacabraham

Yes coreclr is missing a feature.

A bit of history on why downward binding even exists on the desktop:

Before we shipped V1.0 of the CLR there was a scenario that we cared about:

An Application AppA shipped with a dependence on AssemblyB V1.0.0.0. An Application AppB shipped with a dependence on Assembly B V1.0.1.0 and publisher policy Upgrading v1.0.0.0 refs to V1.0.1.0 all policy assemblies and dll's would be installed in the GAC

Now V.1.0.1.0 of B was slightly incompatible with V1.0.0.0 and because of the pub policy AppA was broken.

We actually had in Windows tooling to inject a binding redirect into the app.config for App A, pushing the Binding back down to 1.0.0.0 (it was upgraded by the policy assembly) downgraded again by the binding redirect.

The above scenario was why binding redirects, were designed.

Notice:

  1. Publisher policy was deprecated even before we shipped V1.0 of the CLR so the scenario is essentially invalid "as designed"
  2. The tooling to add binding redirects was removed by the time Clr 2.0 was released, because they weren't actually useful now that policy was deprecated.
  3. In the intervening years app.config binding redirects have become a general purpose binding unification facility.

Today there is still a scenario that is easy on the desktop and impossible on the coreclr. The coreclr binding policy of not allowing downward binds is what makes it impossible on the coreclr, binding redirects solve it on the desktop CLR

Application A

Library C is unable to work with V1.2.0.0 because of a compatibility bug. Library D could successfully work with Library V1.1.0.0 but the author was foolish and compiled with a higher than necessary version of the library and so an Application cannot successfully compose Library C and Library D.

On the desktop a downward binding redirect would allow an application to compose these libraries by fixing the references to 1.1.0.0. On the Coreclr, there is no combination that will work.

There are two possible solutions:

The first is very hard:

  1. Educate the ecco-system to always reference the lowest version necessary of referenced libraries.
  2. Ensure that developers quickly address compatibility bugs

The second is easier:

  1. Change the coreclr to bind to the local assembly regardless of version number. The developers job is to deploy the correct and tested dll, since the bind is not from the shared framework the version check is not really that useful, it either works or crashes the app. Or add binding redirects ....... No please don't do this that would make me sad

If I had a vote, my preference would be educating the ecco-system to do the "right thing". However, right now there is a valid binding scenario on the desktop that is impossible to replicate on the coreclr.

Anyway that is my 2 cents.

Kevin

FransBouma commented 7 years ago

@terrajobst

@FransBouma https://github.com/fransbouma

Ah, I see. Seems like it hasn't bee released through the gallery yet. Go to https://www.nuget.org/downloads and select VS 2015 VSIX v3.6.0 https://dist.nuget.org/visualstudio- 2015-vsix/v3.6.0/NuGet.Tools.vsix . I'll follow up with the NuGet team to see why 3.6 wasn't pushed yet.

Installing that extension indeed made pass that issue (didn't know you could install the nuget client vsix from that site) however then I ran into the issue:

To reference a library that targets .NET Standard 1.5 or higher, you need to install the .NET Standard Build Support extension for the .NET Framework from https://aka.ms/netstandard-build-support-netfx

No idea why, my consoleapp is targeting .net 4.6.2. Well, perhaps for some shims, but really, this isn't a good experience at all. The Nuget client didn't install the package. Installing the 'net standard build support extension' in 2015, restarting the IDE then made Nuget install EF core 2.0 in the .net 4.6.2 targeting consoleapp.

My recommendation would be to push out Update 4 for 2015 with the new nuget and this build extension so people can use .net standard 2.0 stuff in 2015 as they should be able to. How it is now isn't a good experience. Now I personally wouldn't mind people on 2015 not being able to use EF Core 2.0 but that's another story ;) :P

FB
0x53A commented 7 years ago

To reference a library that targets .NET Standard 1.5 or higher, you need to install the .NET Standard Build Support extension for the .NET Framework from https://aka.ms/netstandard-build-support-netfx

Well, I guess that answers part of my questions above.

Opening the msi in Orca, I can see the shims (which answers my other question from above, where the shims actually come from) and a few task dlls / targets files.

Imho this is the worst possible deployment model - now I need to update all buildservers and all developer environments, but if I don't they will fail silently.

The previous model, where the shims were deployed with a nuget package (NETStandard.Library.NETFramework) was slightly better from that perspective.

paul1956 commented 7 years ago

I have a test project (VS2017.3 and after making the changes listed I still get

Reference required to assembly 'System.Runtime, Version=4.0.20.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' containing the type 'ValueType'. Add one to your project.

How do I add this to my project?

Also I can't upgrade any NuGet Package from 2.2 to 2.3.2 without getting too many errors to list. I am targeting 4.6.2 and would like to move to 4.7 and latest CodeAnalysis packages.

esentio commented 7 years ago

@terrajobst

I'm not aware of this issue. Did you uninstall the packages first / did you migrate the contents of the packages.config file into the PackageReference elements?

Oh, now I realized where I made a mistake. My steps to reproduce the issue were:

  1. Create new solution with new unit test project.
  2. Build solution.
  3. There is test method UnitTest1.TestMethod1() generated from the template. It should be visible in Test Explorer.
  4. Delete packages.config.
  5. Close VS.
  6. Edit csproj (vbproj in my case) and put <RestoreProjectStyle>PackageReference</RestoreProjectStyle> there.
  7. Open VS.
  8. Rebuild solution.
  9. There is no test method in Text Explorer anymore.

My problem was: I didn't explicitly reference any Nuget package in test project yet, so I thought there is no need to migrate anything from of packages.config into the PackageReference elements. But there are 2 packages referenced by default in packages.config: MSTest.TestAdapter and MSTest.TestFramework. Migrating them manually fixed the problem (so did referencing them via Nuget Manager as I wrote previously).

Sorry for confusion, my mistake.

bergmeister commented 7 years ago

I just opened an issue in the Xamarin bug tracker here but it seems to be specific to netstandard. I basically converted a Xamarin PCL to netstandard and only using a method from the Newtonsoft.json NuGet package makes the android project throw a compilation exception

Exception while loading assemblies: System.IO.FileNotFoundException: Could not load assembly 'Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. Perhaps it doesn't exist in the Mono for Android profile?
JamesNK commented 7 years ago

Is this issue the cause of https://github.com/JamesNK/Newtonsoft.Json/issues/1423?

daveh101 commented 7 years ago

I logged issue #504, but this maybe seems like a more relevant place to comment.

I have done a bit of playing around, trying to follow the workaround instructions at the top, but even so it still doesn't seem to work.

Here is what I have now done to try and make it all function.

<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Library</OutputType>
    <RootNamespace>MyProject</RootNamespace>
    <AssemblyName>MyProject</AssemblyName>
    <TargetFramework>net471</TargetFramework>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="NETStandard.Library" Version="2.0.0" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="NETStandard2.csproj" />
  </ItemGroup>
</Project>

Firstly, I thought that 4.7.1 was supposed to play nice with NetStandard 2.0, but secondly I am still having to add the manual reference which is surely what the nuget package is supposed to be about.

Is there something that I have got wrong from the instructions above - if so, I can't work out what it is.

daghb commented 7 years ago

If anyone has some contact with the team maintaining the Microsoft.Bcl.Build package, there is an error in the package where it checks for the existence of packages.config.

See https://github.com/NuGet/Home/issues/2913

pauldalyii commented 7 years ago

@terrajobst When you said...

My recommendation is: don't add BR via a package manager. We've worked with the NuGet folks to disable their BR generation as well. It should be generated during build, because that's the only place where all the necessary context is available.

... are you suggesting that we check the "Skip applying binding redirects" checkbox here:

image

sandersaares commented 7 years ago

The automatic binding redirects is a tooling feature to just generate the redirects in the config file, right? I recall it not working for me in some situations for whatever tooling reason and this caused some pain in the past.

Really, what I would desire on this point is a way to tell the runtime to use whatever name-matching assembly I have thrown into the bin directory. I do not want to the runtime to care about versions - whatever assembly lands in my bin directory is what I want the runtime to use (and if there are multiple, I expect it to error and tell me to get my stuff straight). I do not want "higher wins" or any other "smart logic", I just want "I literally put a DLL file with the right name in the bin directory, just use that to serve your human masters, machine".

jainaashish commented 7 years ago

@terrajobst If you currently do have a packages.config, convert the contents to packages references in the project file.

Please update this guidance like below to get the right behavior:

Blackbaud-JonathanBell commented 7 years ago

There seems to be a problem with using Fakes in this new world. If you try to build Fakes for something exposing System.Net.Http.HttpClient, then it fails to generate. Has anyone found a solution for this?

Error CS0430 The extern alias 'snh' was not specified in a /reference option [D:\Files\Visual Studio 2017\Projects\FakesTest\FakesTest\obj\Debug\Fakes\bcldsc\f.csproj] FakesTest D:\Files\Visual Studio 2017\Projects\FakesTest\FakesTest\f.cs

afrischk commented 7 years ago

@Blackbaud-JonathanBell Exactly the same issue for me for the System.Net.Http.HttpClient. But also it seems to be that System.Composition.CompositionContext is affected. Any thoughts on this?

Blackbaud-JonathanBell commented 7 years ago

The issue appears to be because the generated fakes project produces code that references these assemblies w/ an extern alias --- extern alias snh;. The generated project references these assemblies like System.Net.Http which are in this weird transition state and defines the alias for it, but since those assembly references actually get ignored due to this transition magic, then the alias isn't recognized.

No clue how to fix it ...

afrischk commented 7 years ago

Maybe I am wrong, but it seems to be an compiler issue, isn't it?

From what I read you can pass a flag to the compiler telling it the alias/reference like /reference:snh=System.Net.Http.dll. This seems not to be the case. Is there an option to pass this flag to the compiler during Fakes generation?

Could it also be that the compiler does not know which System.Net.Http version to take, when it generates the Fakes? I am using System.Net.Http 4.3.3.0 in a .NetFramework project with .Net 4.7, but maybe there are dependencies left to version 4.0.0.0. I do use <bindingRedirect>, though.

Any thoughts?

davidjward30 commented 7 years ago

We have recently migrated a solution from .NET 4.5 to .NET 4.6.1. Many of the nuget packages we consume are now available as netstandard2.0 which is chosen in preference to net45/net46. This is a breaking change for us as we have a solution containing both C# and C++/CLI projects. The latter can't reference netstandard2.0 libraries. Is there any way to force the selection of net45/net46? (e.g. project change). We are still using packages.config.

Petermarcu commented 7 years ago

@rrelyea @emgarten is there a way to force a certain TFM to be used for a packge in a project?

emgarten commented 7 years ago

is there a way to force a certain TFM to be used for a packge in a project?

There isn't a way to set the TFM per package, only the project TFM is used.

Petermarcu commented 7 years ago

@emgarten in this case they want to target 4.6.1 but want want the .net framework asset from the package as opposed to netstandard for their C++/ CLI project.

@terrajobst any reason C++/CLI can't be made to work with netstandard?

emgarten commented 7 years ago

Many of the nuget packages we consume are now available as netstandard2.0 which is chosen in preference to net45/net46

This shouldn't happen.

If a project is net461 it will favor package assets in this order:

  1. net461 (exact match)
  2. net45 (same framework)
  3. netstandard2.0 (not the same framework, but compatible)

netstandard2.0 would only be used if zero net* assets were available in the package for that asset type. Note that assets are selected individually, so if build has net461 assets but lib only has netstandard2.0 assets then you will still get netstandard2.0 lib assets. It is up to the package author to use the same frameworks for each asset type to make this consistent.

This is true for both PackageReference projects and for packages.config projects.

Petermarcu commented 7 years ago

@davidjward30 sounds like a .NET Framework asset in a package should be preferred over a .NET Standard asset. Is that not what you are seeing?

davidjward30 commented 6 years ago

@Petermarcu @emgarten I've just double checked and I think the problem lies around "portable-net45+win8+wp8+wpa81" which does not appear in your list above.

If I take a .net 4.6.1 framework project (packages.config) and install System.Collections.Immutable 1.4.0, these are the options:

netcoreapp2.0 netstandard1.0 netstandard2.0 portable-net45+win8+wp8+wpa81

.netstandard2.0 is being chosen, where I would expect the last one - particularly as you stated that net45 (same framework) is above netstandard 2.0. FrameworkNuget.zip

davidjward30 commented 6 years ago

Note that System.Collections.Immutable 1.3.1 offers just

netstandard1.0 portable-net45+win8+wp8+wpa81

In this scenario, portable-net45+win8+wp8+wpa81 is chosen. So in summary, upgrading to System.Collections.Immutable 1.4.0 is a breaking change for us.

Petermarcu commented 6 years ago

@emgarten how do the portable TFM's map into the picture? Is this a case where they were mapped to .NET Standard so .NET Standard is winning?

Petermarcu commented 6 years ago

Just to summarize what @davidjward30 is pointing out:

1.3 had: netstandard1.0 portable-net45+win8+wp8+wpa81

1.4 had: netcoreapp2.0 netstandard1.0 netstandard2.0 portable-net45+win8+wp8+wpa81

So 1.4 added: netcoreapp2.0 netstandard2.0

and netcoreapp2.0 is winning over portable-net45+win8+wp8+wpa81

Should 1.4 have included assets for each specific TFM it used to support in order to prevent this from being a breaking change because portable isn't treated as more specific than .NET Standard?

emgarten commented 6 years ago

@davidjward30 the workaround for this is to modify the hint path in your csproj file to reference the portable folder instead of the netstandard2.0 folder in the package. For packages.config projects it is easy to override the tfm selection this way.

portable-* frameworks are the lowest priority when selecting assets, which is why netstandard2.0 is selected from 1.4.

The reason portable-net45+win8+wp8+wpa81 (profile 259) wins over netstandard1.0 is because that portable framework is a special case and able to install netstandard1.0 packages. The table of these portable frameworks with netstandard equivalents is here: https://github.com/dotnet/standard/blob/master/docs/versions.md

I can see how this is a problem for C++ projects, but for most users netstandard2.0 should be a larger surface area over the legacy portable profile 259 unless I'm missing something.

davidjward30 commented 6 years ago

We have a fairly large codebase of 150+ projects. The workaround of modifying the hint path would probably have to be scripted and I'm not sure how long we could continue like that. Is this a workaround we would have to live with indefinitely? We also have plans to move to packagereference

emgarten commented 6 years ago

@davidjward30 you could try updating all references through an msbuild props/targets file that fixes the hint paths.

michael-hawker commented 6 years ago

I see this with .NET Standard 1.4 projects as well using PackageReference. I have a JavaScript UWP app using a Windows Runtime Component which references the .NET Standard libraries and the Nuget dlls don't get copied as part of the build.

Can I update the UWP JavaScript project which default template used package.json to use PackageReference or is that only for pure .NET projects?

tomzorz commented 6 years ago

Any ideas how to fix https://github.com/RevenantX/LiteNetLib/issues/120 above? The binding redirects didn't help (or I did something wrong).

terrajobst commented 6 years ago

@tomzorz

I responded to the issue. Your issue has definitively nothing to do with this issue here as you're using .NET Core and .NET Standard. Binding Redirects are a .NET Framework only thing. It looks like the package you're consuming is authored incorrectly.

terrajobst commented 6 years ago

@michael-hawker

I see this with .NET Standard 1.4 projects as well using PackageReference. I have a JavaScript UWP app using a Windows Runtime Component which references the .NET Standard libraries and the Nuget dlls don't get copied as part of the build.

Can I update the UWP JavaScript project which default template used package.json to use PackageReference or is that only for pure .NET projects?

I haven't looked into UWP and JavaScript consuming a managed WinMD. Are you using a project-to-project reference between the JavaScript project and the C# UWP WinMD project?

michael-hawker commented 6 years ago

@terrajobst Yes, I have the WinMD component project referencing the .NET Standard component, and then the JavaScript UWP project referencing the WinMD component project.

tomzorz commented 6 years ago

@terrajobst ah thanks, I wondered if it was relatable to this one! Appreciate the help!

Timovzl commented 6 years ago

After moving to PackageReference (and toying with AutoGenerateBindingRedirects and GenerateBindingRedirectsOutputType), I am still running into a FileNotFoundException.

I am using the Pkcs11Interop NuGet package, which requires netstandard13 or net4. It is referenced from LibraryProject, which is netstandard2. That project, in turn, is referenced from WebProject, which is net471.

When building and running WebProject, it outputs Pkcs11Interop.dll, but at runtime it tries to load Pkcs11Interop.NetStandard.dll!

Which DLL should be used? I would assume the netstandard one, as the direct consuming project is netstandard.

How do we get the compile time and runtime behaviors to play nice?

Edit: It seems likely that this happens for all similar packages, but that the problem usually stays hidden because the file names are usually identical.

shanselman commented 6 years ago

Still hitting this in 2018. What's the plan to make this suck less?

cblaze22 commented 6 years ago

Ditto

ggirard07 commented 6 years ago

The short-term plan for (1) is to start blocking project-to-project references in Visual Studio 15.4 that will end up crossing the streams between packages.config and PackageReference

Visual Studio 15.5.7 here and there is still no block in the UI to prevent you from doing that crossing.

I added the RestoreProjectStyle without taking too much time to understand it properly after finding it here while I was starting my first project with .Net Standard (thanks for it anyway @shanselman :) ). In fact I didn't realize I had to get ride off the packages.config file and reinstall all my NuGets by adding references back to the .csproj instead. So now back to get ride off packages.config to fix my solution and crossing my finger to not hit any of those limitations and... Oh wait... of course I have packages that use a powershell script, which is not supported yet!!!

If at least the mentioned block in the UI had been there I would have noticed I did something wrong. Instead I learnt about that issue the hard way! I have been waiting for almost 2 years prior to give a try to .Net Core and .Net Standard, thinking it will give them the required time to get mature. Looks like I was wrong and my only workaround now seems to back off .Net Core in my entire solution.

valeriob commented 6 years ago

i share @ggirard07 sentiment. I tried netstandard and hibrid project format approach since mid 2017 and it has way too many gotchas, it's a shame because the new project system is so much better, but this friction does not really allow incremental upgrades of solutions, maybe it's not meant to be, but it's a shame 😄

pankajmishra743 commented 6 years ago

I am new to Visual Studio 2017 and getting a warning in my xamarin project as below Warning NU1701 Package 'ZXing.Net.Mobile 2.3.2' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETStandard,Version=v2.0'. This package may not be fully compatible with your project. Please help me to resolve this issue.......a lot has been suffered by me on this.Please help

zsims commented 6 years ago

@pankajmishra743 your project is targeting .NET Standard 2.0, but ZXing.Net.Mobile is only built for .NET Framework 4.6.1, worth asking the package authors as this issue isn't the place to get help for things like that.

Also worth reading https://docs.microsoft.com/en-us/dotnet/standard/net-standard to familiarize yourself with what .NET Standard is. Scott Hanselman also has a pretty good blog post that summarises (or did summarise, for 2017) the state of .NET Standard/Core/Framework/etc: https://www.hanselman.com/blog/WhatNETDevelopersOughtToKnowToStartIn2017.aspx

mungojam commented 6 years ago

Hitting this after converting a .net framework console exe to the new sdk format even though that is supposed to set up the binding redirects automatically. At least I assume I am, a MethodNotFoundException from a referenced .net standard project when it tries to call out to a DLL in a nuget package even though that DLL is in the output folder.

I think it may be related to the ValueTuple shenanigans where the referenced library uses v1.3.x and the consuming library uses v1.4.0

mtraudt412 commented 6 years ago

I know I am joining this late but the argument that .NET 4.7.1 in some way provides a solution is not satisfying given that we have very recently been told by Microsoft that:

1- For Azure VM scale sets there are no plans to support 4.7.1 with Windows Server 2016 2- For Azure Cloud Services there are no plans to ship 4.7.1 with Web/Worker roles

steuic commented 6 years ago

@FransBouma I had the same problem using NetStandard.Library v2.0.1: The Assembly Binding Log Viewer (aka fuslogvwr) tell me that the assembly loader was unable to load 'System.Threading.Overlapped, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' because cannot find this specific version of this assembly. The same assemly was available with higher major / minor version numbers.

I had this problem for other dlls.

The 'Il Disassembler' (ILDasm) show me that NetStandard.Library v2.0.1 references versions numbers 0.0.0.0 for many other dlls:

netstandard_2_0_0_0-referencesto-versions_0_0_0_0

To resolve this problem I had to add some binding redirect to my app

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Threading.Overlapped" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

I will evaluate use of AutoGenerateBindingRedirects.

mattjohnsonpint commented 6 years ago

This problem reported by a user of one of my libraries here: mj1856/TimeZoneConverter#16. Note that the binding redirect isn't an option since strong naming is not a thing for me, per .net core guidance here, and binding redirects do not work without a strong name token (I think).

mattjohnsonpint commented 6 years ago

@terrajobst - I'm confused by the workaround mentioned at the top. Should I just be able to add <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> to my .net standard class libraries that are published to nuget? I experimented locally, but it doesn't seem to work.

Manually adding a binding redirect in the end-user application does work, but no amount of fiddling with the settings on my side seems to force a binding redirect be created in the end-user's application when they pull in my packages. What am I missing?

Thanks. -Matt

sandersaares commented 6 years ago

This setting needs to be set in the project that packages are installed into.

mattjohnsonpint commented 6 years ago

@sandersaares - tried that. Got bindings generated for Newtonsoft, but not for my library.

mwpowellhtx commented 6 years ago

Is it just me, or is the migration path from Framework to Standard/Core (anything, 1.x, 2.x, etc) a maze that, personally, I'm finding fairly difficult, at best, to navigate, if not downright confusing. In my case, I want to dive into potentially a Roslyn compile time code generation analyzer, but I'm finding that the minimum requirements for that are at least .NET Standard 1.x? Perhaps, it seems there is a plausible bridge from Framework 4.6.x targeted projects along these lines? Or at least from my Analyzers project(s), per se. Thoughts? Suggestions? Recommendations? Thanks!