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

Update cross-plat targeting #38072

Merged
merged 1 commit into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
40 changes: 20 additions & 20 deletions docs/standard/library-guidance/cross-platform-targeting.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Cross-platform targeting for .NET libraries
description: Best practice recommendations for creating cross-platform .NET libraries.
ms.date: 10/27/2023
ms.date: 11/14/2023
---

# Cross-platform targeting
Expand All @@ -13,53 +13,53 @@ Modern .NET supports multiple operating systems and devices. It's important for
.NET and .NET Standard targets are the best way to add cross-platform support to a .NET library.

* [.NET Standard](../net-standard.md) is a specification of .NET APIs that are available on all .NET implementations. Targeting .NET Standard lets you produce libraries that are constrained to use APIs that are in a given version of .NET Standard, which means it's usable by all platforms that implement that version of .NET Standard.
* .NET 5 is an implementation of .NET that Microsoft is actively developing. It's a single product with a uniform set of capabilities and APIs that can be used for Windows desktop apps and cross-platform console apps, cloud services, and websites.
* .NET 6-8 are implementations of .NET. Each version is a single product with a uniform set of capabilities and APIs that can be used for Windows desktop apps and cross-platform console apps, cloud services, and websites.

For more information about how .NET compares to .NET Standard, see [.NET 5 and .NET Standard](../net-standard.md#net-5-and-net-standard).

![.NET Standard](./media/cross-platform-targeting/platforms-netstandard.png ".NET Standard")
![.NET Standard](./media/cross-platform-targeting/platforms-netstandard.png)

Targeting .NET or .NET Standard, and successfully compiling your project, doesn't guarantee the library will run successfully on all platforms:
If your project targets .NET or .NET Standard and compiles successfully, it doesn't guarantee that the library will run successfully on all platforms:

1. Platform-specific APIs will fail on other platforms. For example, <xref:Microsoft.Win32.Registry?displayProperty=nameWithType> will succeed on Windows and throw <xref:System.PlatformNotSupportedException> when used on any other OS.
2. APIs can behave differently. For example, reflection APIs have different performance characteristics when an application uses ahead-of-time compilation on iOS or UWP.
- Platform-specific APIs will fail on other platforms. For example, <xref:Microsoft.Win32.Registry?displayProperty=nameWithType> will succeed on Windows and throw <xref:System.PlatformNotSupportedException> when used on any other OS.
- APIs can behave differently. For example, reflection APIs have different performance characteristics when an application uses ahead-of-time compilation on iOS or UWP.

> [!TIP]
> The .NET team offers a [Platform compatibility analyzer](../analyzers/platform-compat-analyzer.md) to help you discover possible issues.

✔️ DO start with including a `netstandard2.0` target.

> Most general-purpose libraries should not need APIs outside of .NET Standard 2.0. .NET Standard 2.0 is supported by all modern platforms and is the recommended way to support multiple platforms with one target.
> Most general-purpose libraries don't need APIs outside of .NET Standard 2.0. .NET Standard 2.0 is supported by all modern platforms and is the recommended way to support multiple platforms with one target. If you don't need to support .NET Framework, you could also target .NET Standard 2.1.

✔️ DO include a `net5.0` target or later if you require new APIs introduced in a modern .NET.
✔️ DO include a `net6.0` target or later if you require new APIs introduced in a modern .NET.

> .NET 5 or later apps can use a `netstandard2.0` target so `net5.0` isn't required. Explicitly targeting `net5.0` should be added when you want to use new .NET APIs.
> .NET 6 and later apps can use a `netstandard2.0` target, so `net6.0` isn't required. You should explicitly target `net6.0`, `net7.0`, or `net8.0` when you want to use newer .NET APIs.

❌ AVOID including a `netstandard1.x` target.

> .NET Standard 1.x is distributed as a granular set of NuGet packages, which creates a large package dependency graph and results in developers downloading a lot of packages when building. Modern .NET implementations support .NET Standard 2.0. You should only target .NET Standard 1.x if you specifically need to target an older platform.
> .NET Standard 1.x is distributed as a granular set of NuGet packages, which creates a large package dependency graph and results in the download of a lot of packages when building. Modern .NET implementations support .NET Standard 2.0. You should only target .NET Standard 1.x if you specifically need to target an older platform.

✔️ DO include a `netstandard2.0` target if you require a `netstandard1.x` target.

> All platforms supporting .NET Standard 2.0 will use the `netstandard2.0` target and benefit from having a smaller package graph while older platforms will still work and fall back to using the `netstandard1.x` target.

❌ DO NOT include a .NET Standard target if the library relies on a platform-specific app model.

> For example, a UWP control toolkit library depends on an app model that is only available on UWP. App model specific APIs will not be available in .NET Standard.
> For example, a UWP control toolkit library depends on an app model that is only available on UWP. App model specific APIs aren't available in .NET Standard.

## Multi-targeting

Sometimes you need to access framework-specific APIs from your libraries. The best way to call framework-specific APIs is using multi-targeting, which builds your project for many [.NET target frameworks](../frameworks.md) rather than for just one.
Sometimes you need to access framework-specific APIs from your libraries. The best way to call framework-specific APIs is to use multi-targeting, which builds your project for many [.NET target frameworks](../frameworks.md) rather than for just one.

To shield your consumers from having to build for individual frameworks, you should strive to have a .NET Standard output plus one or more framework-specific outputs. With multi-targeting, all assemblies are packaged inside a single NuGet package. Consumers can then reference the same package and NuGet will pick the appropriate implementation. Your .NET Standard library serves as the fallback library that is used everywhere, except for the cases where your NuGet package offers a framework-specific implementation. Multi-targeting allows you to use conditional compilation in your code and call framework-specific APIs.
To shield your consumers from having to build for individual frameworks, you should strive to have a .NET Standard output plus one or more framework-specific outputs. With you multi-target, all assemblies are packaged inside a single NuGet package. Consumers can then reference the same package and NuGet will pick the appropriate implementation. Your .NET Standard library serves as the fallback library that is used everywhere, except for the cases where your NuGet package offers a framework-specific implementation. Multi-targeting allows you to use conditional compilation in your code and call framework-specific APIs.

![NuGet package with multiple assemblies](./media/cross-platform-targeting/nuget-package-multiple-assemblies.png "NuGet package with multiple assemblies")
![NuGet package with multiple assemblies](./media/cross-platform-targeting/nuget-package-multiple-assemblies.png)

✔️ CONSIDER targeting .NET implementations in addition to .NET Standard.

> Targeting .NET implementations allows you to call platform-specific APIs that are outside of .NET Standard.
>
> Do not drop support for .NET Standard when you do this. Instead, throw from the implementation and offer capability APIs. This way, your library can be used anywhere and supports runtime light-up of features.
> Do not drop support for .NET Standard when you do this. Instead, throw from the implementation and offer capability APIs. This way, your library can be used anywhere and supports run-time light-up of features.

```csharp
public static class GpsLocation
Expand Down Expand Up @@ -92,17 +92,17 @@ public static class GpsLocation
}
```

✔️ CONSIDER multi-targeting even if your source code is the same for all targets, when your project has any library / package dependencies.
✔️ CONSIDER multi-targeting even if your source code is the same for all targets, when your project has any library or package dependencies.

> Your project's dependent packages, either direct or downstream, may use the same code APIs while wrapped inside different versions of the dependent assembly per target framework. Adding specific targets ensures that your consumers do not need to add / update their assembly binding redirects.
> Your project's dependent packages, either direct or downstream, might use the same code APIs while wrapped inside different versions of the dependent assembly per target framework. Adding specific targets ensures that your consumers do not need to add or update their assembly binding redirects.

❌ AVOID multi-targeting as well as targeting .NET Standard, if your source code is the same for all targets and your project has no library / package dependencies.
❌ AVOID multi-targeting as well as targeting .NET Standard, if your source code is the same for all targets and your project has no library or package dependencies.

> The .NET Standard assembly will automatically be used by NuGet. Targeting individual .NET implementations increases the `*.nupkg` size for no benefit.

✔️ CONSIDER adding a target for `net461` when you're offering a `netstandard2.0` target.

> Using .NET Standard 2.0 from .NET Framework has some issues that were addressed in .NET Framework 4.7.2. You can improve the experience for developers that are still on .NET Framework 4.6.1 - 4.7.1 by offering them a binary that is built for .NET Framework 4.6.1.
> Using .NET Standard 2.0 from .NET Framework has some issues that were addressed in .NET Framework 4.7.2. You can improve the experience for developers that are still on .NET Framework 4.6.1 - 4.7.1 by offering them a binary that's built for .NET Framework 4.6.1.

✔️ DO distribute your library using a NuGet package.

Expand All @@ -125,7 +125,7 @@ public static class GpsLocation

## Older targets

.NET supports targeting versions of .NET Framework that are long out of support as well as platforms that are no longer commonly used. While there's value in making your library work on as many targets as possible, having to work around missing APIs can add significant overhead. We believe certain frameworks are no longer worth targeting, considering their reach and limitations.
.NET supports targeting versions of .NET Framework that are out of support as well as platforms that are no longer in common use. While there's value in making your library work on as many targets as possible, having to work around missing APIs can add significant overhead. Considering their reach and limitations, certain frameworks are no longer worth targeting.

❌ DO NOT include a Portable Class Library (PCL) target. For example, `portable-net45+win8+wpa81+wp8`.

Expand Down
2 changes: 1 addition & 1 deletion docs/standard/net-standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ For more information, see [.NET Framework compatibility mode](../core/porting/th

## .NET Standard libraries and Visual Studio

In order to build .NET Standard libraries in Visual Studio, make sure you have [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link&utm_content=download+vs2022), [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link&utm_content=download+vs2019), or Visual Studio 2017 version 15.3 or later installed on Windows, or [Visual Studio for Mac version 7.1](https://visualstudio.microsoft.com/vs/mac/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link) or later installed on macOS.
To build .NET Standard libraries in Visual Studio, make sure you have [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link&utm_content=download+vs2022), [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link&utm_content=download+vs2019), or Visual Studio 2017 version 15.3 or later installed on Windows, or [Visual Studio for Mac version 7.1](https://visualstudio.microsoft.com/vs/mac/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link) or later installed on macOS.

If you only need to consume .NET Standard 2.0 libraries in your projects, you can also do that in Visual Studio 2015. However, you need NuGet client 3.6 or higher installed. You can download the NuGet client for Visual Studio 2015 from the [NuGet downloads](https://www.nuget.org/downloads) page.

Expand Down
Loading