When .NET Standard 2.0 was introduced, it wasn't plain sailing. .NET Standard 1.5 and 1.6 were already a thing, and they included APIs from .NET Frameworks higher than .NET Framework 4.6.1. Since .NET Standard releases should always be supersets of the previous releases, it naturally followed that .NET Standard 2.0 would only be supported in .NET Frameworks greater than or equal to 4.7.0, as Standard 1.5 included APIs from Framework 4.6.2, and Standard 1.6 included APIs from Framework 4.6.3.

However Microsoft saw an opportunity to broaden the compatibility of .NET Standard 2.0 to include .NET Framework 4.6.1, this meant changing the existing Framework support levels for .NET Standard 1.5 and 1.6, as they had already been released. This was the direction taken due to the fact that the 4.6.1 runtime was so widely used it would have hindered the adoption and success of .NET Standard, and .NET Core as a result had it been left out.

Having .NET Framework 4.6.1 work with .NET Standard 2.0 packages was very ambitious given that it was already out there in use, support needed to be built retrospectively.

While this mostly worked, in practice I found that there were many problems faced in writing .NET Standard libraries that would run on .NET Framework 4.6.1, and consuming them. Some of the issues I faced were to do with CI build agents not having the necessary versions of nuget and MSBuild to deal with .NET Standard 2.0 libraries, but the larger issues were around assembly binding redirects, and runtime issues, here is just a flavour. There were a number of issues that emerged over time and have become known issues.

Because of all of the issues that I faced, and from other developers stories, the guidance I was giving people last year was to target both netstandard2.0 and net461 at the first sign of trouble if they were really keen on having just one target, or to target both from the beginning for a happy and peaceful life.

Recently Immo Landwerth has said in a tweet that making .NET Standard 2.0 work on .NET Framework 4.6.1 was a mistake, and that the documentation will be updated to reflect the new guidance. He has clarified that it is nothing to do with missing APIs (which is the case for some largely unused APIs in 1.5 & 1.6) but more to do with other issues such as tooling. You can see just some of these issues discussed in this GitHub issue.

There has been a recent drive to move to netstandard2.0 to get the benefits it brings to development time thanks to this recent tweet from David Fowler, which is great advice, but many have opted to take this opportunity to remove net461 or lower, meaning that consumers that update now face some of these problems.


So my recommendation today for library authors that intend to build packages for multiple platforms, including running on net461 - net471, is to target netstandard2.0 and the net4x platform you want to support. .NET Framework 4.7.2 has been built with netstandard2.0 in mind, so it's at that point you can lose the separate target.

If we want to quickly visualise this with the .NET Standard implementation support table, then here's what it looks like:

.NET Standard 2.0 2.1
.NET Core 2.0 3.0
.NET Framework Feasible but problematic: 4.6.1
Works: 4.7.2
TBC (Not 4.8)

If the "Feasible but problematic" part makes you feel uncomfortable, feel free to interpret that as "Does not work". Really it means get ready for possible pain, which is something that as a library author you don't want to unleash on your consumers.

If you are that consumer that is experiencing these issues as a result of running .NET Standard packages on .NET Framework 4.6.1, you should prioritise upgrading to 4.7.2, this will really save you time and pain in the long run. If you aren't directly able to do this, apply pressure to those that are in control of this.

Microsoft will be updating their documentation around this topic with official guidance, and I will be updating this post once that is released.