Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move preview APIs article to runtime libraries section of docs #44436

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
move preview apis article
  • Loading branch information
gewarren committed Jan 19, 2025
commit 44d70a2cde88058a883aef6374e5159538c680c4
4 changes: 4 additions & 0 deletions .openpublishing.redirection.fundamentals.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"source_path_from_root": "/docs/fundamentals/apicompat/package-validation/diagnostic-ids.md",
"redirect_url": "/dotnet/fundamentals/apicompat/diagnostic-ids"
},
{
"source_path_from_root": "/docs/fundamentals/apicompat/preview-apis.md",
"redirect_url": "/dotnet/fundamentals/preview-apis"
},
{
"source_path_from_root": "/docs/fundamentals/code-analysis/quality-rules/ca1071.md",
"redirect_url": "/dotnet/fundamentals/code-analysis/quality-rules/index"
Expand Down
72 changes: 0 additions & 72 deletions docs/fundamentals/apicompat/preview-apis.md

This file was deleted.

69 changes: 69 additions & 0 deletions docs/fundamentals/runtime-libraries/preview-apis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: Preview APIs
description: Learn how to mark .NET APIs as preview.
ms.date: 4/4/2024
---

# Preview APIs

The .NET platform takes compatibility seriously. As such, the library ecosystem tends to avoid making breaking changes, especially with respect to the API.

Nonetheless, when designing APIs, it's important to be able to collect feedback from users and make changes to the API based on that feedback if necessary. To avoid surprises, you should understand which APIs you use are considered stable and which ones are still in active development and might change.

There are multiple ways an API can express to be in preview form:

* The entire component is considered preview if it's exposed:

* In a preview release of the .NET runtime.
* In a prerelease NuGet package.

* An otherwise stable component marks specific APIs as preview with the following attributes:

* <xref:System.Runtime.Versioning.RequiresPreviewFeaturesAttribute>
* <xref:System.Diagnostics.CodeAnalysis.ExperimentalAttribute>

This article explains how each option works, and, for library developers, how to choose between these options.

## .NET runtime previews

With the exception of release candidates (RCs) with a go-live license, preview versions of the .NET runtime and SDK aren't supported.

As such, any APIs added as part of a .NET preview are considered subject to change, based on feedback the previews receive. To use a .NET runtime preview, you need to explicitly target a newer framework version in your project. By doing so, you implicitly express consent to consume APIs that might change.

## Prerelease NuGet packages

NuGet packages can either be stable or *prerelease*. Prerelease packages are marked as such with a prerelease suffix on their version. For example, `System.Text.Json 9.0.0-preview.2.24128.5` has a prerelease suffix of `preview.2.24128.5`.

Prerelease packages are commonly used as a means to collect feedback from early adopters. They are generally unsupported by their author.

When you install a package, either via the CLI or UI, you must explicitly indicate whether you want to install a prerelease version. By doing so, you implicitly express consent to consume APIs that might change.

## `RequiresPreviewFeaturesAttribute`

The <xref:System.Runtime.Versioning.RequiresPreviewFeaturesAttribute> attribute is used for APIs that require preview behaviors across the stack, including the runtime, the C# compiler, and libraries. When you consume APIs marked with this attribute, you'll receive a build error unless your project file includes the property `<EnablePreviewFeatures>true</EnablePreviewFeatures>`. Setting that property to `true` also sets `<LangVersion>Preview</LangVersion>`, which allows the use of preview language features.

As an example, in .NET 6 the *generic math* library was marked with <xref:System.Runtime.Versioning.RequiresPreviewFeaturesAttribute> because it required static interface members, which were in preview at the time.

## `ExperimentalAttribute`

.NET 8 added <xref:System.Diagnostics.CodeAnalysis.ExperimentalAttribute>, which doesn't require any runtime or language preview features and simply indicates that a given API isn't stable yet.

When building against an experimental API, the compiler produces an error. Each feature that's marked as experimental has its own separate diagnostic ID. To express consent to using an experimental API, you suppress the specific diagnostic. You can do that via any of the means for suppressing diagnostics, but the recommended way is to add the diagnostic to the project's `<NoWarn>` property.

Since each experimental feature has a separate ID, consenting to using one experimental feature doesn't consent to using another.

For more information, see [Experimental features][experimental-overview].

## Guidance for library developers

Library developers should generally express that an API is in preview in one of two ways:

* For new APIs introduced in a *prerelease* version of your package, you don't need to do anything; the package already expresses preview quality.
* If you want to ship a stable package that contains some preview quality APIs, you should mark those APIs using `[Experimental]`. Make sure to use [your own diagnostic ID][choosing-diagnostic-ids] and make it specific to those features. If you have multiple independent features, consider using multiple IDs.

The `[RequiresPreviewFeatures]` attribute is only meant for components of the .NET platform itself. Even there, it's only used for APIs that require runtime and language preview features. If it's just an API that's in preview, the .NET platform uses the `[Experimental]` attribute.

The exception to this rule is if you're building a stable library and want to expose certain features that in turn depend on runtime or language preview behaviors. In that case, you should use `[RequiresPreviewFeatures]` for the entry points of that feature. However, you need to consider that users of such APIs have to turn on preview features too, which exposes them to all runtime, library, and language preview behaviors.

[choosing-diagnostic-ids]: ../../csharp/roslyn-sdk/choosing-diagnostic-ids.md
[experimental-overview]: ../syslib-diagnostics/experimental-overview.md
4 changes: 3 additions & 1 deletion docs/fundamentals/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,9 @@ items:
- name: Runtime libraries
items:
- name: Overview
href: ../standard/runtime-libraries-overview.md
href: ../standard/
- name: Preview APIs
href: runtime-libraries/preview-apis.md
- name: Format numbers, dates, other types
items:
- name: Overview
Expand Down
19 changes: 12 additions & 7 deletions docs/standard/library-guidance/versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ms.date: 01/26/2021
---
# Versioning

A software library is rarely complete in version 1.0. Good libraries evolve over time, adding features, fixing bugs, and improving performance. It is important that you can release new versions of a .NET library, providing additional value with each version, without breaking existing users.
A software library is rarely complete in version 1.0. Good libraries evolve over time, adding features, fixing bugs, and improving performance. It's important that you can release new versions of a .NET library without breaking existing users.

## Breaking changes

Expand All @@ -15,25 +15,30 @@ For information about handling breaking changes between versions, see [Breaking

A .NET library has many ways to specify a version. These versions are the most important:

- [NuGet package version](#nuget-package-version)
- [Assembly version](#assembly-version)
- [Assembly file version](#assembly-file-version)
- [Assembly informational version](#assembly-informational-version)

### NuGet package version

The [NuGet package version](/nuget/reference/package-versioning) is displayed on NuGet.org, the Visual Studio NuGet package manager, and is added to source code when the package is used. The NuGet package version is the version number users will commonly see, and they'll refer to it when they talk about the version of a library they're using. The NuGet package version is used by NuGet and has no effect on runtime behavior.
The [NuGet package version](/nuget/reference/package-versioning) is displayed on NuGet.org and the Visual Studio NuGet package manager, and is added to source code when the package is used. The NuGet package version is the version number users will commonly see, and they'll refer to it when they talk about the version of a library they're using. The NuGet package version is used by NuGet and has no effect on runtime behavior.

```xml
<PackageVersion>1.0.0-alpha1</PackageVersion>
```

The NuGet package identifier combined with the NuGet package version is used to identify a package in NuGet. For example, `Newtonsoft.Json` + `11.0.2`. A package with a suffix is a pre-release package and has special behavior that makes it ideal for testing. For more information, see [Pre-release packages](./nuget.md#pre-release-packages).
The NuGet package identifier combined with the NuGet package version is used to identify a package in NuGet. For example, `Newtonsoft.Json` + `11.0.2`. A package with a suffix is a prerelease package and has special behavior that makes it ideal for testing. For more information, see [prerelease packages](./nuget.md#prerelease-packages).

Because the NuGet package version is the most visible version to developers, it's a good idea to update it using [Semantic Versioning (SemVer)](https://semver.org/). SemVer indicates the significance of changes between release and helps developers make an informed decision when choosing what version to use. For example, going from `1.0` to `2.0` indicates that there are potentially breaking changes.
Because the NuGet package version is the most visible version to developers, it's a good idea to update it using [Semantic Versioning (SemVer)](https://semver.org/). SemVer indicates the significance of changes between releases and helps developers make an informed decision when choosing what version to use. For example, going from `1.0` to `2.0` indicates that there are potentially breaking changes.

✔️ CONSIDER using [SemVer 2.0.0](https://semver.org/) to version your NuGet package.

✔️ DO use the NuGet package version in public documentation as it's the version number that users will commonly see.

✔️ DO include a pre-release suffix when releasing a non-stable package.
✔️ DO include a prerelease suffix when releasing a nonstable package. (For more information about marking APIs as preview or experimental, see [Preview APIs](../../fundamentals/runtime-libraries/preview-apis.md).)

> Users must opt in to getting pre-release packages, so they will understand that the package is not complete.
> Users must opt in to getting prerelease packages, so they understand that the package is not complete.

### Assembly version

Expand All @@ -45,7 +50,7 @@ The assembly version is what the CLR uses at run time to select which version of

The .NET Framework CLR demands an exact match to load a strong-named assembly. For example, `Library1, Version=1.0.0.0` was compiled with a reference to `Newtonsoft.Json, Version=11.0.0.0`. .NET Framework will only load that exact version `11.0.0.0`. To load a different version at run time, a binding redirect must be added to the .NET application's config file.

Strong naming combined with assembly version enables [strict assembly version loading](../assembly/versioning.md). While strong naming a library has a number of benefits, it often results in run-time exceptions that an assembly can't be found and [requires binding redirects](../../framework/configure-apps/redirect-assembly-versions.md) in `app.config` or `web.config` to be fixed. In .NET Core, assembly loading is more relaxed. The .NET Core runtime automatically loads assemblies with a higher version at run time.
Strong naming combined with assembly version enables [strict assembly version loading](../assembly/versioning.md). While strong naming a library has a number of benefits, it often results in run-time exceptions that an assembly can't be found and [requires binding redirects](../../framework/configure-apps/redirect-assembly-versions.md) in `app.config` or `web.config` to be fixed. In .NET (Core), assembly loading is more relaxed. The .NET (Core) runtime automatically loads assemblies with a higher version at run time.

✔️ CONSIDER only including a major version in the AssemblyVersion.

Expand Down