Announcing .NET Standard 2.1
Since we shipped .NET Standard 2.0 about a year ago, we’ve shipped two updates to .NET Core 2.1 and are about to release .NET Core 2.2. It’s time to update the standard to include some of the new concepts as well as a number of small improvements that make your life easier across the various implementations of .NET.
Keep reading to learn more about what’s new in this latest release, what you need to know about platform support, governance and coding.
What’s new in .NET Standard 2.1?
In total, about 3k APIs are planned to be added in .NET Standard 2.1. A good chunk of them are brand-new APIs while others are existing APIs that we added to the standard in order to converge the .NET implementations even further.
Here are the highlights:
- Span<T>. In .NET Core 2.1 we’ve added
Span<T>which is an array-like type that allows representing managed and unmanaged memory in a uniform way and supports slicing without copying. It’s at the heart of most performance-related improvements in .NET Core 2.1. Since it allows managing buffers in a more efficient way, it can help in reducing allocations and copying. We consider
Span<T>to be a very fundamental type as it requires runtime and compiler support in order to be fully leveraged. If you want to learn more about this type, make sure to read Stephen Toub’s excellent article on
- Foundational-APIs working with spans. While
Span<T>is available as a .NET Standard compatible NuGet package (
System.Memory) already, adding this package cannot extend the members of .NET Standard types that deal with spans. For example, .NET Core 2.1 added many APIs that allow working with spans, such as
Stream.Read(Span<Byte>). Part of the value proposition to add span to .NET Standard is to add theses companion APIs as well.
- Reflection emit. To boost productivity, the .NET ecosystem has always made heavy use of dynamic features such as reflection and reflection emit. Emit is often used as a tool to optimize performance as well as a way to generate types on the fly for proxying interfaces. As a result, many of you asked for reflection emit to be included in the .NET Standard. Previously, we’ve tried to provide this via a NuGet package but we discovered that we cannot model such a core technology using a package. With .NET Standard 2.1, you’ll have access to Lightweight Code Generation (LCG) as well as Reflection Emit. Of course, you might run on a runtime that doesn’t support running IL via interpretation or compiling it with a JIT, so we also exposed two new capability APIs that allow you to check for the ability to generate code at all (
RuntimeFeature.IsDynamicCodeSupported) as well as whether the generated code is interpreted or compiled (
RuntimeFeature.IsDynamicCodeCompiled). This will make it much easier to write libraries that can exploit these capabilities in a portable fashion.
- SIMD. .NET Framework and .NET Core had support for SIMD for a while now. We’ve leveraged them to speed up basic operations in the BCL, such as string comparisons. We’ve received quite a few requests to expose these APIs in .NET Standard as the functionality requires runtime support and thus cannot be provided meaningfully as a NuGet package.
ValueTask<T>. In .NET Core 2.1, the biggest feature was improvements in our fundamentals to support high-performance scenarios, which also included making
ValueTask<T>already exists and allows to return results if the operation completed synchronously without having to allocate a new
Task<T>. With .NET Core 2.1 we’ve improved this further which made it useful to have a corresponding non-generic
ValueTaskthat allows reducing allocations even for cases where the operation has to be completed asynchronously, a feature that types like
NetworkStreamnow utilize. Exposing these APIs in .NET Standard 2.1 enables library authors to benefit from these improvements both, as a consumer, as well as a producer.
- DbProviderFactories. In .NET Standard 2.0 we added almost all of the primitives in ADO.NET to allow O/R mappers and database implementers to communicate. Unfortunately,
DbProviderFactoriesdidn’t make the cut for 2.0 so we’re adding it now. In a nutshell,
DbProviderFactoriesallows libraries and applications to utilize a specific ADO.NET provider without knowing any of its specific types at compile time, by selecting among registered
DbProviderFactoryinstances based on a name, which can be read from, for example, configuration settings.
- General Goodness. Since .NET Core was open sourced, we’ve added many small features across the base class libraries such as
System.HashCodefor combining hash codes or new overloads on
System.String. There are about 800 new members in .NET Core and virtually all of them got added in .NET Standard 2.1.
For more details, you might want to check out the full API diff between .NET Standard 2.1 and .NET Standard 2.0. You can also use apisof.net to quickly check whether a given API will be included with .NET Standard 2.1.
.NET platform support
In case you missed our Update on .NET Core 3.0 and .NET Framework 4.8, we’ve described our support for .NET Framework and .NET Core as follows:
.NET Framework is the implementation of .NET that’s installed on over one billion machines and thus needs to remain as compatible as possible. Because of this, it moves at a slower pace than .NET Core. Even security and bug fixes can cause breaks in applications because applications depend on the previous behavior. We will make sure that .NET Framework always supports the latest networking protocols, security standards, and Windows features.
.NET Core is the open source, cross-platform, and fast-moving version of .NET. Because of its side-by-side nature it can take changes that we can’t risk applying back to .NET Framework. This means that .NET Core will get new APIs and language features over time that .NET Framework cannot. At Build we showed a demo how the file APIs are faster on .NET Core. If we put those same changes into .NET Framework we could break existing applications, and we don’t want to do that.
Given many of the API additions in .NET Standard 2.1 require runtime changes in order to be meaningful, .NET Framework 4.8 will remain on .NET Standard 2.0 rather than implement .NET Standard 2.1. .NET Core 3.0 as well as upcoming versions of Xamarin, Mono, and Unity will be updated to implement .NET Standard 2.1.
Library authors who need to support .NET Framework customers should stay on .NET Standard 2.0. In fact, most libraries should be able to stay on .NET Standard 2.0, as the API additions are largely for advanced scenarios. However, this doesn’t mean that library authors cannot take advantage of these APIs even if they have to support .NET Framework. In those cases they can use multi-targeting to compile for both .NET Standard 2.0 as well as .NET Standard 2.1. This allows writing code that can expose more features or provide a more efficient implementation on runtimes that support .NET Standard 2.1 while not giving up on the bigger reach that .NET Standard 2.0 offers.
For more recommendations on targeting, check out the brand new documentation on cross-platform targeting.
The .NET Standard 1.x and 2.0 releases focused on exposing existing concepts. The bulk of the work was on the .NET Core side, as this platform started with a much smaller API set. Moving forward, we’ll often have to standardize brand-new technologies, which means we need to consider the impact on all .NET implementations, not just .NET Core, and including those managed in other communities such as Mono or Unity. Our governance model has been updated to best include all considerations, including:
A .NET Standard review board. To ensure we don’t end up adding large chunks of API surface that cannot be implemented, a review board will sign-off on API additions to the .NET Standard. The board comprises representatives from .NET platform, Xamarin and Mono, Unity and the .NET Foundation and will be chaired by Miguel de Icaza. We will continue to strive to make decisions based on consensus and will leverage Miguel’s extensive expertise and experience building .NET implementations that are supported by multiple parties when needed.
A formal approval process. The .NET Standard 1.x and 2.0 version were largely mechanically derived by computing which APIs existing .NET implementations had in common, which means the API sets were effectively a computational outcome. Moving forward, we are implementing an editorial approach:
- Anyone can submit proposals for API additions to the .NET Standard.
- New members on standardized types are automatically considered. To prevent accidental fragmentation, we’ll automatically consider all members added by any .NET implementation on types that are already in the standard. The rationale here is that divergence at that the member level is not desirable and unless there is something wrong with the API it’s likely a good addition.
- Acceptance requires:
- A sponsorship from a review board member. That person will be assigned the issue and is expected to shepherd the issue until it’s either accepted or rejected. If no board member is willing to sponsor the proposal, it will be considered rejected.
- A stable implementation in at least one .NET implementation. The implementation must be licensed under an open source license that is compatible with MIT. This will allow other .NET implementations to jump- start their own implementations or simply take the feature as-is.
- .NET Standard updates are planned and will generally follow a set of themes. We avoid releases with a large number of tiny features that aren’t part of a common set of scenarios. Instead, we try to define a set of goals that describe what kind of feature areas a particular .NET Standard version provides. This simplifies answering the question which .NET Standard a given library should depend on. It also makes it easier for .NET implementations to decide whether it’s worth implementing a higher version of .NET Standard.
- The version number is subject to discussion and is generally a function of how significant the new version is. While we aren’t planning on making breaking changes, we’ll rev the major version if the new version adds large chunks of APIs (like when we doubled the number of APIs in .NET Standard 2.0) or has sizable changes in the overall developer experience (like the added compatibility mode for consuming .NET Framework libraries we added in .NET Standard 2.0).
For more information, take a look at the .NET Standard governance model and the .NET Standard review board.
The definition of .NET Standard 2.1 is ongoing. You can watch our progress on GitHub and still file requests.
If you want to quickly check whether a specific API is in .NET Standard (or any other .NET platform), you can use apisof.net. You can also use the .NET Portability Analyzer to check whether an existing project or binary can be ported to .NET Standard 2.1.
I can’t help but think this breaks the basic point of .NET Standard.
I thought it’s core point was to describe common APIs between .NET and .NET Core.
Is there a reason to have it if .NET and .NET Core are never going to be together on it again?
This is the last straw for me, despite claiming otherwise it’s pretty clear that Microsoft is very close to EoL for the .NET Framework. Now that .NET Core will support WPF and Windows Forms it doesn’t look like they need to support it anymore. It looks like they’ll keep .NET Standard around for compatibility with 3rd party libraries like Unity. It looks like it’s time to move anything we can on to .NET Core. The only reason .NET Framework has current libraries is because of the .NET Standard compatibility, without that new development on .NET Framework is a very bad idea. Selling management on porting .NET MVC apps to .NET Core is going to be “fun”.
I agree i feel they have completely lost the point of standard. which is allowing framework and core to talk together, or core to talk to framework.
You can stick with .Net Standard 2.0 for those common parts. the new stuff can go in standard 2.1+
I don’t think this is acceptable… well in my eyes, let me explain.
I’m all for going forward, but systems are complex and there a many moving parts.
So what happened recently was they made EF6 compatibly…. well not really as now it requires 2.1 which is not compatible with framework (which seems completely, like the opposite of the point of why so many wanted EF6 on Standard/core).
I was under the impression that the whole point of doing EF6 to Support standard was allow those who are in the process of migrating everything do not have to do everything at once as that is just too much.
just seems super dumb, as E6 is still basically tired to core as most who are on standard or core already would of been using ef6 core already.
If they just made a version of Ef6 compatible with (standard which is compatible with framework)… i think they would help 100’s of ppl with the most common migration issues.
im stuck again because of this and its really disappointing form MS.
I fell into the same problem as Calvin Nel in that I want to share some of my business logic between our .NET Framework and .NET Core yet EF6 only works in .NET Standard 2.1… Useless to me. Guess I have to stick with having duplicate business logic between .NET Core and .NET Framework.
Informative article, thank you.
Re the following statement from the blog post…
Given many of the API additions in .NET Standard 2.1 require runtime changes in order to be meaningful, .NET Framework 4.8 will remain on .NET Standard 2.0 rather than implement .NET Standard 2.1
… and also …
NET Framework is the implementation of .NET that’s installed on over one billion machines and thus needs to remain as compatible as possible. Because of this, it moves at a slower pace than .NET Core.
The first statement implies that development on .NET Framework has not just slowed, but rather almost stopped.
Will the .NET Framework ever support a version of .NET Standard greater than .NET Standard 2.0?
It seems to me that .NET Framework is basically maintenance only and potentially only very big Windows changes that would break compatibility if not implemented.
Those comments especially don’t make sense in the light of the fact that with the creation of .NET Framework one of its major advantages touted was the elimination of DLL Hell by allowing side to side installationo of incompatible versions. All they would need to do is create a major new .Net Framework version 5.0 that installs side by side with 4, just like 2.0 or 3.5 did.
I agree this could be done, however my interpretation is this won’t happen.
See this page: https://github.com/dotnet/standard/blob/master/docs/versions.md
In particlar the footnote: “.NET Framework will not support .NET Standard 2.1 or any other later version.”
This either means there will be no .NET Framework 5 or if there is, it won’t be compatible with the current .NET Standard version at that time (which would make little sense).
I agree with you, and I am saying their justification isn’t believable. Now we know .Net 5 will not be compatible with .Net 4.8 but will be compatible with .Net Standard 2.1 because it will essentially be .Net Core 4.
What is the entry point to submit an API proposal for .NET standard? Opening an issue on dotnet/standard githut repository?
So we are locked out of C# 8 and features like nullable references and compiler checks for them just because we target the most widely used .NET Framework? Bummer.
If library authors wants to use nullable reference types, they must upgrade to .NET Standard 2.1? Which lock libraries out of .NET Framework?
It’s an unsupported hack, but if you migrate your .NET Framework project to use the SDK project format, you can set 8.0 and enable. See https://stackoverflow.com/a/57020770/111794 .
Wow … DotNet Framework really is dead 🙁
Ever since I saw at Build last year that everything was going to be .Net Core by November of this year, I started moving code to .Net Core.
I have a list of 6 things now that I wanted to hate .Net Core about, but each time the new way is faster and easier, so it is getting harder to hate .Net Core.
Nuget packages are especially easier. Click a check box and click build, and the code in my graphics program I just ported today is about 5 times faster.
The one beef I have is the same as this thread. I have 15+ years of .Net Framework code, and my choice is either support both .Net Framework and Core, or list the .Net Framework as obsolete. It seems like there should be a .Net Standard 3.1 at the same time there is a Dot Net Core 3.1, that supports .Net Framework at least back to 4.6.1, which is so common you can’t find a Windows 10 machine that doesn’t have it unless it has been locked in a closet for 7 or 8 years.
As usual, Microsoft kills it’s own technology, not allowing net framework 2.1 works with .net framework 4.8. Shame on you.
It’s now April, 2020. We still can’t use .Net Standard 2.1 on UWP. Why so awfully slow?