Announcing .NET Standard 2.1

Avatar

Immo

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 Span<T>.
  • 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 and ValueTask<T>. In .NET Core 2.1, the biggest feature was improvements in our fundamentals to support high-performance scenarios, which also included making async/await more efficient. 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 ValueTask that allows reducing allocations even for cases where the operation has to be completed asynchronously, a feature that types like Socket and NetworkStream now 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, DbProviderFactories didn’t make the cut for 2.0 so we’re adding it now. In a nutshell, DbProviderFactories allows libraries and applications to utilize a specific ADO.NET provider without knowing any of its specific types at compile time, by selecting among registered DbProviderFactory instances 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.HashCode for 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.

Governance model

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.

Summary

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.

Happy coding!

Avatar
Immo Landwerth

Program Manager, .NET

Follow Immo   

8 comments

  • Avatar
    Schaff, Stephen

    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?

    • Avatar
      Jonathan Bruce

      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”.

  • Chris Bailiss
    Chris Bailiss

    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.
     

    • Avatar
      Pete Wilson

      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.

      • Chris Bailiss
        Chris Bailiss

        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).

        • Avatar
          Pete Wilson

          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.

  • Avatar
    Jozef Izso

    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?

Leave a comment