|
| 1 | +--- |
| 2 | +title: What's new in .NET 8 |
| 3 | +description: Learn about the new .NET features introduced in .NET 8. |
| 4 | +titleSuffix: "" |
| 5 | +ms.date: 02/21/2023 |
| 6 | +ms.topic: overview |
| 7 | +ms.author: gewarren |
| 8 | +author: gewarren |
| 9 | +--- |
| 10 | +# What's new in .NET 8 |
| 11 | + |
| 12 | +.NET 8 is the successor to [.NET 7](dotnet-7.md). It will be [supported for three years](https://dotnet.microsoft.com/platform/support/policy/dotnet-core) as a long-term support (LTS) release. |
| 13 | + |
| 14 | +This article has been updated for .NET 8 Preview 1. |
| 15 | + |
| 16 | +> [!IMPORTANT] |
| 17 | +> |
| 18 | +> - This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here. |
| 19 | +> - Most of the other .NET documentation on <https://learn.microsoft.com> has not yet been updated for .NET 8. |
| 20 | +
|
| 21 | +## 'dotnet publish' and 'dotnet pack' |
| 22 | + |
| 23 | +Since the [`dotnet publish`](../tools/dotnet-publish.md) and [`dotnet pack`](../tools/dotnet-pack.md) commands are intended to produce production assets, they now produce `Release` assets by default. |
| 24 | + |
| 25 | +The following output shows the different behavior between `dotnet build` and `dotnet publish`, and how you can revert to publishing `Debug` assets by setting the `PublishRelease` property to `false`. |
| 26 | + |
| 27 | +```console |
| 28 | +/app# dotnet new console |
| 29 | +/app# dotnet build |
| 30 | + app -> /app/bin/Debug/net8.0/app.dll |
| 31 | +/app# dotnet publish |
| 32 | + app -> /app/bin/Release/net8.0/app.dll |
| 33 | + app -> /app/bin/Release/net8.0/publish/ |
| 34 | +/app# dotnet publish -p:PublishRelease=false |
| 35 | + app -> /app/bin/Debug/net8.0/app.dll |
| 36 | + app -> /app/bin/Debug/net8.0/publish/ |
| 37 | +``` |
| 38 | + |
| 39 | +For more information, see ['dotnet pack' uses Release config](../compatibility/sdk/8.0/dotnet-pack-config.md) and ['dotnet publish' uses Release config](../compatibility/sdk/8.0/dotnet-publish-config.md). |
| 40 | + |
| 41 | +## System.Text.Json serialization |
| 42 | + |
| 43 | +Various improvements have been made to <xref:System.Text.Json?displayProperty=fullName> serialization and deserialization functionality. |
| 44 | + |
| 45 | +- Performance and reliability enhancements of the [source generator](../../standard/serialization/system-text-json/source-generation.md) when used with ASP.NET Core in Native AOT apps. |
| 46 | +- The [source generator](../../standard/serialization/system-text-json/source-generation.md) now supports serializing types with [`required`](../../standard/serialization/system-text-json/required-properties.md) and [`init`](../../csharp/language-reference/keywords/init.md) properties. These were both already supported in reflection-based serialization. |
| 47 | +- [Customize handling of members that aren't in the JSON payload.](../../standard/serialization/system-text-json/missing-members.md) |
| 48 | +- Support for serializing properties from interface hierarchies. The following code shows an example where the properties from both the immediately implemented interface and its base interface are serialized. |
| 49 | + |
| 50 | + ```csharp |
| 51 | + IDerived value = new Derived { Base = 0, Derived =1 }; |
| 52 | + JsonSerializer.Serialize(value); // {"Base":0,"Derived":1} |
| 53 | +
|
| 54 | + public interface IBase |
| 55 | + { |
| 56 | + public int Base { get; set; } |
| 57 | + } |
| 58 | + |
| 59 | + public interface IDerived : IBase |
| 60 | + { |
| 61 | + public int Derived { get; set; } |
| 62 | + } |
| 63 | + |
| 64 | + public class Derived : IDerived |
| 65 | + { |
| 66 | + public int Base { get; set; } |
| 67 | + public int Derived { get; set; } |
| 68 | + } |
| 69 | + ``` |
| 70 | + |
| 71 | +- <xref:System.Text.Json.JsonNamingPolicy> includes new naming policies for `snake_case` (with an underscore) and `kebab-case` (with a hyphen) property name conversions. Use these policies similarly to the existing <xref:System.Text.Json.JsonNamingPolicy.CamelCase?displayProperty=nameWithType> policy: |
| 72 | + |
| 73 | + ```csharp |
| 74 | + var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower }; |
| 75 | + JsonSerializer.Serialize(new { PropertyName = "value" }, options); // { "property_name" : "value" } |
| 76 | + ``` |
| 77 | + |
| 78 | + - JsonSerializer.MakeReadOnly() gives you explicit control over when a JsonSerializerOptions instance is frozen. (Also check it with IsReadOnly.) |
| 79 | + |
| 80 | +For more information about JSON serialization in general, see [JSON serialization and deserialization in .NET](../../standard/serialization/system-text-json/overview.md). |
| 81 | + |
| 82 | +## Methods for working with randomness |
| 83 | + |
| 84 | +The <xref:System.Random?displayProperty=fullName> and <xref:System.Security.Cryptography.RandomNumberGenerator?displayProperty=fullName> types introduce two new methods for working with randomness. |
| 85 | + |
| 86 | +### GetItems\<T>() |
| 87 | + |
| 88 | +The new `System.Random.GetItems<T>()` and `System.Security.Cryptography.RandomNumberGenerator.GetItems<T>()` methods let you randomly choose a specified number of items from an input set. The following example shows how to use `System.Random.GetItems<T>()` (on the instance provided by the <xref:System.Random.Shared?displayProperty=nameWithType> property) to randomly insert 31 items into an array. This example could be used in a game of "Simon" where players must remember a sequence of colored buttons. |
| 89 | + |
| 90 | +```csharp |
| 91 | +private static ReadOnlySpan<Button> s_allButtons = new[] |
| 92 | +{ |
| 93 | + Button.Red, |
| 94 | + Button.Green, |
| 95 | + Button.Blue, |
| 96 | + Button.Yellow, |
| 97 | +}; |
| 98 | + |
| 99 | +... |
| 100 | + |
| 101 | +Button[] thisRound = Random.Shared.GetItems(s_allButtons, 31); |
| 102 | +// Rest of game goes here ... |
| 103 | +``` |
| 104 | + |
| 105 | +### Shuffle\<T>() |
| 106 | + |
| 107 | +The new `System.Random.Shuffle<T>()` and `System.Security.Cryptography.RandomNumberGenerator.Shuffle<T>()` methods let you randomize the order of a span. These methods are useful for reducing training bias in machine learning (so the first thing isn't always training, and the last thing always test). |
| 108 | + |
| 109 | +```csharp |
| 110 | +YourType[] trainingData = LoadTrainingData(); |
| 111 | +Random.Shared.Shuffle(trainingData); |
| 112 | + |
| 113 | +IDataView sourceData = mlContext.Data.LoadFromEnumerable(trainingData); |
| 114 | + |
| 115 | +DataOperationsCatalog.TrainTestData split = mlContext.Data.TrainTestSplit(sourceData); |
| 116 | +model = chain.Fit(split.TrainSet); |
| 117 | + |
| 118 | +IDataView predictions = model.Transform(split.TestSet); |
| 119 | +// ... |
| 120 | +``` |
| 121 | + |
| 122 | +## Performance-focused types |
| 123 | + |
| 124 | +.NET 8 introduces several new types aimed at improving app performance. |
| 125 | + |
| 126 | +- The new `System.Collections.Frozen` namespace includes the collection types `FrozenDictionary<TKey, TValue>` and `FrozenSet<T>`. These types don't allow any changes to keys and values once a collection created. That requirement allows faster read operations (for example, `TryGetValue()`). These types are particularly useful for collections that are populated on first use and then persisted for the duration of a long-lived service, for example: |
| 127 | + |
| 128 | + ```csharp |
| 129 | + private static readonly FrozenDictionary<string, bool> s_configurationData = |
| 130 | + LoadConfigurationData().ToFrozenDictionary(optimizeForReads: true); |
| 131 | + // ... |
| 132 | + if (s_configurationData.TryGetValue(key, out bool setting) && setting) |
| 133 | + { |
| 134 | + Process(); |
| 135 | + } |
| 136 | + ``` |
| 137 | + |
| 138 | +- The new `IndexOfAnyValues<T>` type is designed to be passed to methods that look for the first occurrence of any value in the passed collection. For example, <xref:System.String.IndexOfAny(System.Char[])?displayProperty=nameWithType> looks for the first occurrence of any character in the specified array in the `string` it's called on. NET 8 adds new overloads of methods like <xref:System.String.IndexOfAny%2A?displayProperty=nameWithType> and <xref:System.MemoryExtensions.IndexOfAny%2A?displayProperty=nameWithType> that accept an instance of the new type. When you create an instance of `IndexOfAnyValues<T>`, all the data that's necessary to optimize subsequent searches is derived, so the work is done up front. |
| 139 | +- The new `CompositeFormat` type is useful for optimizing format strings that aren't known at compile time (for example, if the format string is loaded from a resource file). A little extra time is spent up front to do work such as parsing the string, but it saves the work from being done on each use. |
| 140 | + |
| 141 | + ```csharp |
| 142 | + private static readonly CompositeFormat s_rangeMessage = CompositeFormat.Parse(LoadRangeMessageResource()); |
| 143 | + // ... |
| 144 | + static string GetMessage(int min, int max) => |
| 145 | + string.Format(CultureInfo.InvariantCulture, s_rangeMessage, min, max); |
| 146 | + ``` |
| 147 | + |
| 148 | +- New `XxHash3` and `XxHash128` types provide implementations of the fast XXH3 and XXH128 hash algorithms. |
| 149 | + |
| 150 | +## System.Numerics and System.Runtime.Intrinsics |
| 151 | + |
| 152 | +This section covers improvements to the <xref:System.Numerics?displayProperty=fullName> and <xref:System.Runtime.Intrinsics?displayProperty=fullName> namespaces. |
| 153 | + |
| 154 | +- <xref:System.Runtime.Intrinsics.Vector256%601>, <xref:System.Numerics.Matrix3x2>, and <xref:System.Numerics.Matrix4x4> have improved hardware acceleration on .NET 8. For example, <xref:System.Runtime.Intrinsics.Vector256%601> was reimplemented to internally be `2x Vector128<T>` operations, where possible. This allows partial acceleration of some functions when `Vector128.IsHardwareAccelerated == true` but `Vector256.IsHardwareAccelerated == false`, such as on Arm64. |
| 155 | +- .NET 8 includes the initial implementation of `Vector512<T>`. |
| 156 | +- Hardware intrinsics are now annotated with the `ConstExpected` attribute. This ensures that users are aware when the underlying hardware expects a constant and therefore when a non-constant value may unexpectedly hurt performance. |
| 157 | +- The `Lerp` API has been added to <xref:System.Numerics.IFloatingPointIeee754%601> and therefore to `float` (<xref:System.Single>), `double` (<xref:System.Double>), and <xref:System.Half>. This API allows a linear interpolation between two values to be performed efficiently and correctly. |
| 158 | + |
| 159 | +## Native AOT |
| 160 | + |
| 161 | +The option to [publish as native AOT](../deploying/native-aot/index.md) was first introduced in .NET 7. Publishing an app with native AOT creates a fully self-contained version of your app that doesn't need a runtime—everything is included in a single file. |
| 162 | + |
| 163 | +.NET 8 adds support for the x64 and Arm64 architectures on *macOS*. |
| 164 | + |
| 165 | +Also, the sizes of native AOT apps on Linux are now up to 50% smaller. The following table shows the size of a "Hello World" app published with native AOT that includes the entire .NET runtime on .NET 7 vs. .NET 8: |
| 166 | + |
| 167 | +| Operating system | .NET 7 | .NET 8 Preview 1 | |
| 168 | +| ------------------------------------- | ------- | ---------------- | |
| 169 | +| Linux x64 (with -p:StripSymbols=true) | 3.76 MB | 1.84 MB | |
| 170 | +| Windows x64 | 2.85 MB | 1.77 MB | |
| 171 | + |
| 172 | +## Code generation |
| 173 | + |
| 174 | +.NET 8 includes improvements to code generation and just-in time (JIT) compilation: |
| 175 | + |
| 176 | +- Arm64 performance improvements |
| 177 | +- SIMD improvements |
| 178 | +- Cloud-native improvements |
| 179 | +- Profile-guided optimization (PGO) improvements |
| 180 | +- Support for AVX-512 ISA extensions |
| 181 | +- JIT throughput improvements |
| 182 | +- Loop and general optimizations |
| 183 | + |
| 184 | +## .NET container images |
| 185 | + |
| 186 | +The following changes have been made to .NET container images for .NET 8: |
| 187 | + |
| 188 | +- The container images now use [Debian 12 (Bookworm)](https://wiki.debian.org/DebianBookworm). Debian is the default Linux distro in the .NET container images. |
| 189 | +- Images include a `non-root` user. This user makes the images `non-root` capable. To run as `non-root`, add the following line at the end of your Dockerfile (or a similar instruction in your Kubernetes manifests): |
| 190 | + |
| 191 | + ```dockerfile |
| 192 | + USER app |
| 193 | + ``` |
| 194 | + |
| 195 | + The default port also changed from port `80` to `8080`. To support this change, a new environment variable `ASPNETCORE_HTTP_PORTS` is available to make it easier to change ports. The variable accepts a list of ports, which is simpler than the format required by `ASPNETCORE_URLS`. If you change the port back to port `80` using one of these variables, you can't run as `non-root`. |
| 196 | +- Preview container images tags now have a `-preview` suffix instead of just using the version number. For example, to pull the .NET 8 Preview SDK, use the following tag: |
| 197 | + |
| 198 | + `docker run --rm -it mcr.microsoft.com/dotnet/sdk:8.0-preview` |
| 199 | + |
| 200 | + The `-preview` suffix will be removed for release candidate (RC) releases. |
| 201 | + |
| 202 | +- [Chiseled Ubuntu images](https://hub.docker.com/r/ubuntu/dotnet-deps) are available for .NET 8. Chiseled images have a reduced attacked surface because they're ultra-small, have no package manager or shell, and are `non-root`. This type of image is for developers that want the benefit of appliance-style computing. Chiseled images are published to the [.NET nightly artifact registry](https://mcr.microsoft.com/product/dotnet/nightly/aspnet/tags). |
| 203 | + |
| 204 | +## Build your own .NET on Linux |
| 205 | + |
| 206 | +In previous .NET versions, you could build .NET from source, but it required you to create a "source tarball" from the [dotnet/installer](https://github.com/dotnet/installer) repo commit that corresponded to a release. In .NET 8, that's no longer necessary and you can build .NET on Linux directly from the [dotnet/dotnet](https://github.com/dotnet/dotnet) repository. That repo uses [dotnet/source-build](https://github.com/dotnet/source-build) to build .NET runtimes, tools, and SDKs. This is the same build that Red Hat and Canonical use to build .NET. |
| 207 | + |
| 208 | +Building in a container is the easiest approach for most people, since the `dotnet-buildtools/prereqs` container images contain all the required dependencies. For more information, see the [build instructions](https://github.com/dotnet/dotnet#building). |
| 209 | + |
| 210 | +## Minimum support baselines for Linux |
| 211 | + |
| 212 | +The minimum support baselines for Linux have been updated for .NET 8: |
| 213 | + |
| 214 | +- .NET will be built targeting Ubuntu 16.04, for all architectures. That's primarily important for defining the minimum `glibc` version for .NET 8. For example, .NET 8 will fail to even start on Ubuntu 14.04. |
| 215 | +- For Red Hat Enterprise Linux (RHEL), .NET supports RHEL 8+ and drops RHEL 7. |
| 216 | + |
| 217 | +For more information, see [Red Hat Enterprise Linux Family support](https://github.com/dotnet/core/blob/main/linux-support.md#red-hat-enterprise-linux-family-support). |
| 218 | + |
| 219 | +## See also |
| 220 | + |
| 221 | +- [Breaking changes in .NET 8](../compatibility/8.0.md) |
| 222 | +<!-- - [.NET blog: Announcing .NET 8 Preview 1](https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-1/)--> |
| 223 | +<!-- - [.NET blog: ASP.NET Core updates in .NET 8 Preview 1](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-8-preview-1/) --> |
0 commit comments