Standard: Understanding why there is no cleaner way than .NET Framework 4.6.1 supporting .NET Standard 2.0

Created on 20 Dec 2016  Â·  35Comments  Â·  Source: dotnet/standard

Edit: This discussion is only worth reading if you want to understand why there is no cleaner way than .NET Framework 4.6.1 supporting .NET Standard 2.0 to unlock the 20k+ additional APIs in .NET Standard 2.0. None of my proposals can be realized.

The spec on .NET Standard 2.0 plans .NET Framework 4.6.1 to implement .NET Standard 2.0 even though 43 APIs of .NET Standard 2.0 will not be implemented by .NET Framework 4.6.1.

The motivation for this sloppy solution seems to be that it is assumed that .NET Standard 2.0 will be widely targeted and .NET Framework 4.6.1 a very attractive .NET platform to support:

This would mean that the libraries compiled against .NET Standard 2.0 would not run on the vast majority of .NET Framework installations.

.NET Framework 4.6.1 has the highest adoption, which makes it the most attractive version of .NET Framework to target.

The motivation is understandable, but that solution really devaluates the .NET Standard and I believe that there may be a better non-breaking solution:

Introduce ".NET Standard 1.7" (a strict superset of .NET Standard 1.6) with all the 14,994 APIs that .NET Standard 2.0 is planning to add and .NET Framework 4.6.1 already supports. Add the remaining 43 APIs that .NET Framework 4.6.1 doesn't support to .NET Standard 2.0 (a strict superset of .NET Standard 1.7).

This would be a clean - even simpler - solution with all the benefits of the currently planned solution and none of its problems:

  • .NET Standard 2.0 will be a strict superset of .NET Standard 1.7. In other words, no breaking changes will happen between .NET Standard 2.0 and 1.x.
  • .NET Framework 4.6.1 will allow referencing binaries that are compiled against .NET Standard 1.7.

Notice how the bold 1.7 now replaces both 1.6 and 2.0, respectively, in your quoted spec. I did not change anything else in these two bullet points. And the API port scan would not longer be required.

While my proposal would make .NET Standard 1.7 specific to .NET Framework 4.6.1 (which is against the philosophy of .NET Standard) it is not as bad as creating real technical issues in the .NET Standard only to have the .NET Framework 4.6.1 target .NET Standard 2.0.

If you do go with my proposal, then you could even introduce .NET Standard 1.8 to support APIs specific to .NET Framework 4.6.2 (if that was important) since .NET Standard versions 1.7 - 1.9 are skipped/unused anyway with the current plans of the .NET Standard. You could also just rename .NET Standard 2.0 to .NET Standard 1.8 or 1.9 since .NET Standard 2.0 would not break anything anyway (and the current justification for incrementing the major version number is rather silly - and confusing for .NET Standard beginners).

Does my proposal have any problems that I have missed?

Most helpful comment

Here is the problem we were facing:

  • .NET Framework 4.6.1 only supports .NET Standard 1.4.

    • .NET Standard 1.5 and .NET Standard 1.6 have APIs that .NET Famework 4.6.1 doesn't have yet.

  • That number of APIs is very low (< 100 APIs)
  • 100% of the APIs that we want to add to .NET Standard are already supported by .NET Framework 4.6.1, and that's a very large number (~20,000 APIs)

We've two options:

  1. Violate the linear versioning of .NET Standard and make .NET Standard 2.0 remove the ~100 APIs that .NET Framework 4.6.1 doesn't have yet
  2. Let binaries/packages that target .NET Standard 2.0 bind/load on .NET Framework 4.6.1 and accept that a very small number of APIs will not work

We originally tried option (1) but we realized after talking to the community that this way is more complicated than option (2):

  • The complicated versioning rules of option (1) would stay around for a long time and affect all .NET platforms implementing the standard
  • Option (2) only affects .NET Framework and only for some time: eventually, there will be an update to .NET Framework that will add these APIs and the problem will disappear.

Hence, we went with option 2. Does this make sense?

Let me answer a few of your comments directly:

These [missing] APIs might not be popular now as they have been recently added to .NET, but future libraries compiled against .NET Standard 2.0 are most likely going to call those APIs just because they are part of .NET Standard 2.0. This would result in exactly the same undesirable outcome that the .NET Standard 2.0 spec is trying to avoid since these libraries would not run on .NET Framework 4.6.1 without throwing exceptions

That's correct in principle but there is one more item that will likely limit the impact: a good number of theses new APIs were alternatives to the APIs that we're bringing back in .NET Standard 2.0. Existing code that's being ported to .NET Standard is unlikely to use the new alternatives, as the existing ones are now also available. And for new code, one could make a compelling argument that the sheer size of documentation and number of code samples for APIs that were introduced more than decade ago will also likely steer developers towards using the existing APIs as well.

Now of course, I'm not claiming that our plan is perfect, but I do claim that given our constraints and the probabilities for issues our plan is the best compromise.

targeting a modified .NET Standard 1.5 that I suggested in my previous comment could be a viable solution.

In a sense, that's what we're doing. .NET Framework 4.6.1 implements a "modified" version of .NET Standard 2.0, which is excluding the APIs that it doesn't have.

If you're suggesting that we go back change the definition of .NET Standard 1.5 and .NET Standard 1.6 to exclude these APIs then that's a breaking change within .NET Standard and would affect people that built libraries targeting that version of the standard. Keep in mind that except for .NET Standard 2.0 all the platforms and standard versions we're talking about here were already shipped, including .NET Framework 4.6.1. Since we don't have a time machine we've to model how they were defined; we can't change their definition anymore.

All 35 comments

Isn't the problem that .NET Standard 1.6 as it was defined already has the 43 API's in it that are not in .NET 4.6.1? Therefore they would have to be in 1.7 if its a strict superset. The problem is that you can't both add and subtract API's and still version linearly. @terrajobst and @weshaggard can confirm.

Please excuse my possibly nonsensical proposals, but I just want to discuss all options before settling on a sub-optimal solution that we will have to live with forever.

@Petermarcu Thank you for your comment. Do you have an official source or can someone else in an official capacity confirm this?

If that is indeed the problem, then I would suggest that .NET Framework 4.6.1 should target a modified .NET Standard 1.5 where the 43 APIs are excluded since the .NET Standard 1.5 is not directly targeted by any other .NET platform right now. Is this possible or are there also known problems with that?

Another option would be to offer a compatibility pack like the one for PCLs as a Nuget package where you would be able to target an earlier .NET Standard version (e.g. 1.5, 1.4) and the compatibility pack would add the remaining APIs for .NET Framework 4.6.1 or 4.6.2. A future .NET Framework version could then target .NET Standard 2.0 or a future .NET Standard version directly.

If there are problems with all of my previous proposals, then a last resort would be to decide that .NET Framework 4.6.1 does not target any .NET Standard if it cannot reliably do that. A future version of .NET Framework could target .NET Standard 2.0 or a future .NET Standard version.

Happy to discuss and make sure it all makes sense. I can pull some data from some other sources tomorrow to confirm what I mentioned. I just don't have it in front of me right now.

All the outcomes require some version of the standard dropping some of the API's because they were accidentally added before we had a clear picture of how .NET Standard needed to evolve in the context of .NET Framework.

We want .NET Standard to be usable by people when we release it and we believe that .NET 4.6.1 will be the version that most people have installed on Windows by the time we ship. That drove a requirement that .NET Standard 2.0 had to target .NET Framework 4.6.1. The requirement is driven a little backwards for this release because, different from previous .NET Standards, we are being far more intentional about making it broadly applicable so the ecosystem of libs has as easy a time as possible moving forward. The 43 API's that are orphaned are not very popular as they have only been recently added to .NET so we made the decision to orphan those from .NET Standard 2.0 in favor of making sure that building on top of .NET Standard 2.0 is a no-brainer for libraries as soon as it ships.

The forces should reverse once .NET Standard 2.0 ships and we can make intentional decisions about what gets added to the Standard considering all the platforms that would need to implement it.

I hope that made sense and we appreciate the feedback and passion for doing the right thing!

All the outcomes require some version of the standard dropping some of the API's because they were accidentally added before we had a clear picture of how .NET Standard needed to evolve in the context of .NET Framework.

If the 43 APIs that are not supported by .NET Framework 4.6.1 were indeed added in .NET Standard 1.6, then targeting a modified .NET Standard 1.5 that I suggested in my previous comment could be a viable solution. Are there any problems with that?

We want .NET Standard to be usable by people when we release it and we believe that .NET 4.6.1 will be the version that most people have installed on Windows by the time we ship. That drove a requirement that .NET Standard 2.0 had to target .NET Framework 4.6.1.

This is a very pragmatic reason that I understand, but there might be a solution that will not cause problems in the future.

The 43 API's that are orphaned are not very popular as they have only been recently added to .NET so we made the decision to orphan those from .NET Standard 2.0 in favor of making sure that building on top of .NET Standard 2.0 is a no-brainer for libraries as soon as it ships.

There is a problem with that rational. These 43 APIs might not be popular now as they have been recently added to .NET, but future libraries compiled against .NET Standard 2.0 are most likely going to call those APIs just because they are part of .NET Standard 2.0. This would result in exactly the same undesirable outcome that the .NET Standard 2.0 spec is trying to avoid since these libraries would not run on .NET Framework 4.6.1 without throwing exceptions:

Quotes from the spec of .NET Standard 2.0:

By following normal versioning rules one would expect that .NET Standard 2.0 would only be supported by a newer version of .NET Framework, given that .NET Framework 4.6.1 only implements .NET Standard 1.4.
This would mean that the libraries compiled against .NET Standard 2.0 would not run on the vast majority of .NET Framework installations.

So the current plan is in fact a non-solution that will just cause additional problems in the future.

So the current plan is in fact a non-solution that will just cause additional problems in the future.

This isn't the plan, it sounds like an explanation of what could have happened if we didn't define .NET Standard 2.0 as something that .NET 4.6.1 supports.

If the 43 APIs that are not supported by .NET Framework 4.6.1 were indeed added in .NET Standard 1.6, then targeting a modified .NET Standard 1.5 that I suggested in my previous comment could be a viable solution. Are there any problems with that?

I believe they were added in 1.4, 1.5, and 1.6. A little in each. Again, I'll have to pull up the data. From what I understand, your suggestion is to go back to whatever version we added them in, redefine that version to not have those API's, then linearly version from there up to 2.0 without the problematic API's. Am I understanding your suggestion correctly?

Here is the problem we were facing:

  • .NET Framework 4.6.1 only supports .NET Standard 1.4.

    • .NET Standard 1.5 and .NET Standard 1.6 have APIs that .NET Famework 4.6.1 doesn't have yet.

  • That number of APIs is very low (< 100 APIs)
  • 100% of the APIs that we want to add to .NET Standard are already supported by .NET Framework 4.6.1, and that's a very large number (~20,000 APIs)

We've two options:

  1. Violate the linear versioning of .NET Standard and make .NET Standard 2.0 remove the ~100 APIs that .NET Framework 4.6.1 doesn't have yet
  2. Let binaries/packages that target .NET Standard 2.0 bind/load on .NET Framework 4.6.1 and accept that a very small number of APIs will not work

We originally tried option (1) but we realized after talking to the community that this way is more complicated than option (2):

  • The complicated versioning rules of option (1) would stay around for a long time and affect all .NET platforms implementing the standard
  • Option (2) only affects .NET Framework and only for some time: eventually, there will be an update to .NET Framework that will add these APIs and the problem will disappear.

Hence, we went with option 2. Does this make sense?

Let me answer a few of your comments directly:

These [missing] APIs might not be popular now as they have been recently added to .NET, but future libraries compiled against .NET Standard 2.0 are most likely going to call those APIs just because they are part of .NET Standard 2.0. This would result in exactly the same undesirable outcome that the .NET Standard 2.0 spec is trying to avoid since these libraries would not run on .NET Framework 4.6.1 without throwing exceptions

That's correct in principle but there is one more item that will likely limit the impact: a good number of theses new APIs were alternatives to the APIs that we're bringing back in .NET Standard 2.0. Existing code that's being ported to .NET Standard is unlikely to use the new alternatives, as the existing ones are now also available. And for new code, one could make a compelling argument that the sheer size of documentation and number of code samples for APIs that were introduced more than decade ago will also likely steer developers towards using the existing APIs as well.

Now of course, I'm not claiming that our plan is perfect, but I do claim that given our constraints and the probabilities for issues our plan is the best compromise.

targeting a modified .NET Standard 1.5 that I suggested in my previous comment could be a viable solution.

In a sense, that's what we're doing. .NET Framework 4.6.1 implements a "modified" version of .NET Standard 2.0, which is excluding the APIs that it doesn't have.

If you're suggesting that we go back change the definition of .NET Standard 1.5 and .NET Standard 1.6 to exclude these APIs then that's a breaking change within .NET Standard and would affect people that built libraries targeting that version of the standard. Keep in mind that except for .NET Standard 2.0 all the platforms and standard versions we're talking about here were already shipped, including .NET Framework 4.6.1. Since we don't have a time machine we've to model how they were defined; we can't change their definition anymore.

@21c-HK thanks for the great feedback we really appreciate folks trying to grasp all the constraints we are working under here and suggest potential solutions.

I agree with @terrajobst's summary of the problems and the compromises we are making. One additional thing I would call out is if we went with a modified netstandard1.5 approach, beyond the breaking change of removing APIs, we couldn't easily add the large amount of APIs that we are adding to netstandard2.0 there either because the other platforms that are targeting netstandard1.5 don't have them (i.e. .NET Core 1.0/1.1 in particular). So netstandard1.5 would still not be very useful for library developers to target as it would still be pretty limited in the number of APIs it would have.

@21c-HK let us know what you think, but I think we should close this issue as I don't think there is a better way of modelling .NET Standard 2.0 and .NET Framework 4.6.1.

@terrajobst That's the first explanation that convinces me we're on the right path. Thank you!

@Petermarcu

First of all, thank you for being supportive and actually being open to my suggestions.

This isn't the plan, it sounds like an explanation of what could have happened if we didn't define .NET Standard 2.0 as something that .NET 4.6.1 supports.

This is not what I meant. I understand that this is not the plan, but this is still going to happen. Just because .NET Standard 2.0 claims to "support" .NET Framework 4.6.1, does not mean programs using libraries compiled against .NET Standard 2.0 are actually going to _run_ on .NET Framework 4.6.1. You might define "run" or "support" differently than me, but it is not unreasonable to expect that "run" or "support" means that a program using that library is not going to crash on .NET Framework 4.6.1 when the same program does not crash on other supported .NET platforms.

I believe they were added in 1.4, 1.5, and 1.6. A little in each. Again, I'll have to pull up the data

Please do. I would really like to be able to understand the details that lead to the current plan being the only viable option. I was already aware of the motivation and decision that @terrajobst re-iterated in this thread before I started this discussion.

@21c-HK

What data would you like to see beyond what I mentioned above? .NET Standard 1.5 and 1.6 combined add ~100 APIs that .NET Framework 4.6.1 doesn't have. On the other hand, .NET Standard 2.0 adds ~20,000 APIs that .NET Framework 4.6.1 already has.

Just because .NET Standard 2.0 claims to "support" .NET Framework 4.6.1

Nit, but it's the other way around: a .NET platform claims a specific version of .NET Standard. It's like your USB ports. Some ports support USB 2.0 while some others support USB 3.0. The standard doesn't know which of your laptop's USB ports it supports, but the specific ports know which version of the spec they implement.

programs using libraries compiled against .NET Standard 2.0 [might not actually] run on .NET Framework 4.6.1

That is correct and is the trade-off I explained. We could say that .NET Framework 4.6.1 only implements .NET Standard 1.4 (which is how it looks like in the shipped version). That means our tools would prevent you from using libraries targeting .NET Standard 2.0. This would guarantee that your app never uses any libraries that could call APIs that .NET Framework 4.6.1 doesn't have.

The problem is that we'd like to give folks that built a .NET Standard-based class library the ability to call the newly added 20,000 APIs while still being able to consume such a library from .NET Framework 4.6.1.

We believe that guarding 100 APIs that don't work at the expense of also blocking 20,000 APIs that would work is unacceptable.

@terrajobst

Thank you for re-iterating your motivation and decision tree in detail and commenting on my objection.

That's correct in principle but there is one more item that will likely limit the impact: a good number of theses new APIs were alternatives to the APIs that we're bringing back in .NET Standard 2.0. Existing code that's being ported to .NET Standard is unlikely to use the new alternatives, as the existing ones are now also available. And for new code, one could make a compelling argument that the sheer size of documentation and number of code samples for APIs that were introduced more than decade ago will also likely steer developers towards using the existing APIs as well.

I may be misunderstanding this because I am not sure what exactly you are referring to when you use "new" and "existing" APIs. My current interpretation does not help me understand how these two points address my objection. Let me simplify the issue with a concrete example, which might help us come to a common understanding:

I author a _new_ library that targets .NET Standard 2.0 where I use some of those 43 APIs that are missing from .NET Framework 4.6.1, because they appear in Intellisense in Visual Studio. I do not target a specific .NET platform, because I believe that .NET Standard allows me to write cross-platform libraries. I publish the library as a NuGet package on nuget.org, which is listed as implementing .NET Standard 2.0. Another developer pulls in my library because she wants to write a cross-platform app. The other developer tests on some .NET platform supported by .NET Standard 2.0, but does not test it on .NET Framework 4.6.1. She is content that everything works. She releases the app and advertises it as cross-platform. She copies the information from the platform support table to inform her users about the supported platforms. One or more of her users run it on .NET Framework 4.6.1 and report that the "cross-platform" app crashes on Windows, because my library that the app uses calls an API that is not supported on .NET Framework 4.6.1. The other developer is confused because she has 100% code coverage and her app only crashes on Windows - the most popular OS for .NET.

Do you really find this situation acceptable?

You have not commented on my option that uses a compatibility pack similar to how PCLs are supported in .NET Standard:

Another option would be to offer a compatibility pack like the one for PCLs as a Nuget package where you would be able to target an earlier .NET Standard version (e.g. 1.5, 1.4) and the compatibility pack would add the remaining APIs for .NET Framework 4.6.1 or 4.6.2. A future .NET Framework version could then target .NET Standard 2.0 or a future .NET Standard version directly.

For example, library A compiled against .NET Standard 1.4 and referencing the compatibility pack can call those additional 20k APIs in .NET Standard 2.0, but not other libraries compiled against .NET Standard 2.0. But library B compiled against the .NET Standard 2.0 could call library A.

A similar but different option that I mentioned in another issue (#123):
Introduce ".NET Standard 2.0 Limited for .NET Framework support", a subset of .NET Standard 2.0 where those 43 APIs are missing. This way library authors could formalize their intention to target a subset of .NET Standard 2.0 specifically to be able to support .NET Framework 4.6.1. Libraries compiled against .NET Standard 2.0 could reuse libraries compiled against ".NET Standard 2.0 Limited for .NET Framework support", but not the other way around.

because they appear in Intellisense in Visual Studio

We have discussed hiding them in intellisense. I still think thats a good option we should explore.

The other developer tests on some .NET platform supported by .NET Standard 2.0, but does not test it on .NET Framework 4.6.1.

.NET Standard does not save you from testing your application or library on the platforms that you would like to support. There are thousand different ways that one can write .NET Standard compliant code that will only work on subset of platforms or runtimes targeted by the given .NET Standard.

@terrajobst

You posted your last comment just a few seconds before I posted my last comment, so I would like to address your last comment here:

What data would you like to see beyond what I mentioned above? .NET Standard 1.5 and 1.6 combined add ~100 APIs that .NET Framework 4.6.1 doesn't have.

How many of those were added in .NET Standard 1.5 and .NET Standard 1.6, respectively?

That means our tools would prevent you from using libraries targeting .NET Standard 2.0. This would guarantee that your app never uses any libraries that could call APIs that .NET Framework 4.6.1 doesn't have.

I realize that you have not had the chance to read my last comment yet, but how would tooling prevent the example I mentioned in my last comment. I don't see how it could, because the library author never intended the library to run on .NET Framework 4.6.1, but the app author cannot know that. This is why it may make sense to offer a "subset edition" of the .NET Standard 2.0 in parallel to the .NET Standard 2.0 (see my last comment) to formalize the actual dependencies somehow. That way, each developer can decide how attractive .NET Framework 4.6.1 is for them. I would even expect the "subset edition" of .NET Standard 2.0 to be more popular than .NET Standard 2.0. I don't see any problems with that approach. Do you?

@Petermarcu

Intellisense cannot help, because .NET Framework 4.6.1 would not be targeted explicitely as I mentioned in my example:

I do not target a specific .NET platform, because I believe that .NET Standard allows me to write cross-platform libraries.

If I target .NET platform 2.0 as a library author, then I expect Intellisense to show me all the APIs of .NET Standard 2.0 (as long as I don't specifically restrict it to .NET Framework 4.6.1, which I did not in the fictitious example).

If they were hidden from Intellisense then people could compile against them if they went out of their way but they wouldn't call them by accident as easily.

Having a subset edition will mean another "profile mapping" and a fracture in the library ecosystem. Its basically giving up and saying that we made a mistake by adding some API's to .NET Standard too early. We want to go back in time but can't so we need to model it like a tree instead of a linear versioning story. I'd much rather have a very simple long term story at the expense of a few warts in the first round. Once newer versions of .NET Framework get adoption in the OS, 4.6.1 will phase out and so will this problem.

It really just doesn't feel worth it for a very small number of newer API's. These API's aren't like the other 20,000 we added back where significant parts of the library ecosystem depend on them.

How many of those were added in .NET Standard 1.5 and .NET Standard 1.6, respectively?

I don't know the break down between .NET Standard 1.5 and .NET Standard 1.6. But .NET Standard 1.6 is a superset of .NET Standard 1.5 and .NET Standard 1.6 has ~100 APIs that .NET Framework 4.6.1 doesn't have. I don't know how many of them were already in .NET Standard 1.5, but why would that break down matter? It's no like you can insert a version in between.

I realize that you have not had the chance to read my last comment yet, but how would tooling prevent the example I mentioned in my last comment.

Please read my explanation again. I was talking about a world in which our tooling considers .NET Framework 4.6.1 to only implement .NET Standard 1.4. That version of .NET Standard doesn't expose any APIs that .NET Framework doesn't have, that's why.

This is why it may make sense to offer a "subset edition" of the .NET Standard 2.0 in parallel to the .NET Standard 2.0

I'd argue it doesn't because you've to decide where on the version line you put the specialized version of .NET Standard. In other words, you have to decide what the relationship is between the subset edition and regular .NET Standard. For example, let's say I create a library that targets that subset:

  • Can I reference .NET Standard 1.5 or 1.6? The only correct answer is "no", otherwise you might use libraries that use APIs that .NET Framework 4.6.1 doesn't have. However, that has the version complications I mentioned above.
  • Can I reference .NET Standard 2.0 (the full version)? The only correct answer is "no". However, the vast majority of libraries would most likely simply target the regular 2.0 version -- not because they need the APIs in the delta, but because it has a simpler name is thus more likely to be used.

Your subset edition is the option (1) I listed earlier:

  • Violate the linear versioning of .NET Standard and make .NET Standard 2.0 remove the ~100 APIs that .NET Framework 4.6.1 doesn't have yet
  • Let binaries/packages that target .NET Standard 2.0 bind/load on .NET Framework 4.6.1 and accept that a very small number of APIs will not work

@Petermarcu

If they were hidden from Intellisense then people could compile against them if they went out of their way but they wouldn't call them by accident as easily.

I don't understand what you mean? Could you elaborate by referring to my fictitious example?

Its basically giving up and saying that we made a mistake by adding some API's to .NET Standard too early.

Well, that's what actually happened :-).

Once newer versions of .NET Framework get adoption in the OS, 4.6.1 will phase out and so will this problem.

How about the following when .NET Framework 4.6.1 no longer has the highest adoption:
Change the platform support table back to show .NET Framework implementing .NET Standard 1.4 only, so that library authors in the future are encouraged to target a higher .NET Standard that is implemented by the most popular .NET Framework version then.

@terrajobst I submit to your arguments. You win ;-).

They are good arguments that make sense.

This has been a good conversation :)

How about the following when .NET Framework 4.6.1 no longer has the highest adoption:
Change the platform support table back to show .NET Framework implementing .NET Standard 1.4 only...

I think that may be interesting from a documentation perspective but I assume the tools would still let you reference a .NET Standard 2.0 library when targeting .NET 4.5.1 because if we didn't allow that, people that had working solutions would start breaking. If this turns out to be a problem, we'll come up with some way in tooling to help people know when they go out of bounds.

That's true. May be an additional warning in the tooling then is enough to make developers aware of that.

Also, there is value in having docs that are "only" 99.99% correct and ignore the 0.01% case, instead of trying to overcompensate :-)

Unhappy to miss this conversation :(.

However, I think another way to solve this is marking netstandard1.5 and 1.6 as depracated. And tell everyone not to target/implement these two.

However, I think another way to solve this is marking netstandard1.5 and 1.6 as depracated. And tell everyone not to target/implement these two.

But that doesn't solve the general problem of who can reference whom. In a sense, time is fixing the problem anyways as a future version of .NET Framework will add the tiny amount of APIs that are currently missing. I still believe it makes more sense to leave the standard as-is and simply consider the specific .NET Standard 2.0 implementation (.NET Framework 4.6.1) to be one with a footnote -- with the understanding that this will be eventually be addressed.

FWIW, this issue was recently discussed on the MVP insider alias and I responded with this:

Our original approach was what you suggested: only expose APIs in .NET Standard that are in .NET Framework 4.6.1. We’ve received a ton of feedback and gave it much more thought.

We concluded that it complicates the versioning of .NET Standard. It means now and moving forward every library author has to assume that a platform supporting .NET Standard 2.0 may not have the 100 or so APIs – regardless of whether they run on .NET Framework 4.6.1.

That seems broken. Considering that .NET Standard 2.0 has 33k APIs it doesn’t seem to be the right trade off to add conceptual complexity that only affects 0.003% of its APIs. Even more so because most of these APIs are brand new and thus not used by many libraries yet.

There is nothing about these APIs that would prevent us from implementing them in .NET Framework. It’s only a point in time problem. A future version of .NET Framework will be 100% .NET Standard 2.0 compliant. At that point this oddity becomes a footnote in the history book rather than a permanent complication for the standard.

Let’s not forget that for the vast majority of our .NET customers .NET Standard is already too complicated. Given that folks have a hard time reasoning about the “clean” world where .NET Standard is fully backwards compatible I believe adding another dimension (major version breakage) will make people’s head explode.

.NET is about being approachable and simple. And simplicity means not going after purity when the vast majority of our customers wouldn’t be affected by it. So instead we decided to have a straight forward versioning strategy for .NET Standard: only additive, no breaking changes. That means shifting the concern from the standard as a whole to a particular implementation. We believe this is a much better and pragmatic choice.

/cc @benaadams @NickCraver @onovotny

I've also been playing with implementing a Roslyn-based diagnostic analyzer that can give you rapid feedback in the IDE but will also provide warnings when building outside (e.g. the build server):

Huge interest in the analyzer. Please make it a standard tool.

I think the easiest way to look at it is:

4.6.1 supports .NET Standard 2.0.

After 4.6.1's release, 52 of the new methods/types have been identified as having an implementation bug and will throw an exception; which will be resolved in a future point release. (semver and all 😉)

However, it perfectly supports the standard and all methods and types for any library that was developed against full framework.

If you developed a library that only worked on .NET Core and couldn't run on full framework, you might want to check the list to make sure you won't be caught out by these bugged functions.

I think the reason Microsoft guys went to ship .net standard 2.0 quickly and implement it in .net 4.6.1 (rather unusual as everyone is talking about), along with missing 43 apis, is because they now know exactly what happens when they ship the first version, millions of millions of nuget downloads, and it's very hard to go back to fix something when there are so many developers using them.

They made a big decision, based on the highly adopted .net version (4.6.1), they are introducing huge change to the .net standard (hence major version number increase 2.0), and they want everyone to adopt it quickly and move onto the next thing based on it.

That's what I think, and good luck, .NET! and everyone in this discussion!

To add more confusion, I have found the following updated chart here: https://docs.microsoft.com/en-us/dotnet/standard/library
screen shot 2017-06-06 at 20 18 41
But it is not clearly stated how to achieve that. I have downloaded .net Core 2.0 Preview and now my .net application accepts to compile against netstandard 1.6 libraries, but then it throws a rutime error:

System.IO.FileNotFoundException:
Could not load file or assembly 'System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies

Any clue how to make it work?

The tooling is in progress but I believe you can add a reference to https://dotnet.myget.org/feed/dotnet-core/package/nuget/NETStandard.Library.NETFramework in your .NET Framework project for now.

@Petermarcu If I try to do that in a net461 project I will get a restore error:

C:\Program Files\dotnet\sdk\2.0.0-preview1-005977\NuGet.targets(97,5): error : Unable to resolve 'NETStandard.Library.NETFramework (>= 2.1.0-preview2-25319-04)' for '.NETFramework,Version=v4.6.1'.

I have to point out that I was able to compile .net 4.6.2 with netstandard 1.5

do you have the feed for myget in your nuget.config?

trying to install it through nuget.exe gave me more errors. I am rolling back everything. This simply doesn't look safe. I think it is not adequate to publish versioning information that is not fully supported yet.

Perhaps that row needs to be updated to say "preview" until the 2.0 tooling is released? @richlander @terrajobst

Perhaps that row needs to be updated to say "preview" until the 2.0 tooling is released?

Fixed with https://github.com/dotnet/docs/pull/2371.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Jmales picture Jmales  Â·  3Comments

chrisaut picture chrisaut  Â·  3Comments

juscelior picture juscelior  Â·  3Comments

praeclarum picture praeclarum  Â·  5Comments

virzak picture virzak  Â·  4Comments