diff --git a/docs/core/whats-new/dotnet-8.md b/docs/core/whats-new/dotnet-8.md index 7448b0be81e10..d4b3bf25aa003 100644 --- a/docs/core/whats-new/dotnet-8.md +++ b/docs/core/whats-new/dotnet-8.md @@ -2,7 +2,7 @@ title: What's new in .NET 8 description: Learn about the new .NET features introduced in .NET 8. titleSuffix: "" -ms.date: 06/13/2023 +ms.date: 07/11/2023 ms.topic: overview ms.author: gewarren author: gewarren @@ -11,149 +11,79 @@ author: gewarren .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. You can [download .NET 8 here](https://dotnet.microsoft.com/download/dotnet). -This article has been updated for .NET 8 Preview 5. +This article has been updated for .NET 8 Preview 6. > [!IMPORTANT] > > - 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. > - Much of the other .NET documentation on [https://learn.microsoft.com/dotnet](/dotnet) has not yet been updated for .NET 8. -## .NET SDK changes - -This section contains the following subtopics: - -- [Terminal build output](#terminal-build-output) -- [Simplified output paths](#simplified-output-paths) -- ['dotnet workload clean' command](#dotnet-workload-clean-command) -- ['dotnet publish' and 'dotnet pack' assets](#dotnet-publish-and-dotnet-pack-assets) -- [Template engine](#template-engine) -- [Source Link](#source-link) -- [Source-build SDK](#source-build-sdk) - -### Terminal build output - -`dotnet build` has a new option to produce more modernized build output. This *terminal logger* output groups errors with the project they came from, better differentiates the different target frameworks for multi-targeted projects, and provides real-time information about what the build is doing. To opt into the new output, use the `--tl` option. For more information about this option, see [dotnet build options](../tools/dotnet-build.md#options). - -### Simplified output paths - -.NET 8 introduces an option to simplify the output path and folder structure for build outputs. Previously, .NET apps produced a deep and complex set of output paths for different build artifacts. The new, simplified output path structure gathers all build outputs into a common location, which makes it easier for tooling to anticipate. - -To opt into the new output path format, use one of the following properties in your *Directory.Build.props* file: +## Serialization -- Add an `ArtifactsPath` property with a value of `$(MSBuildThisFileDirectory)artifacts` (or whatever you want the folder location to be), OR -- To use the default location, simply set the `UseArtifactsOutput` property to `true`. +Many improvements have been made to serialization and deserialization functionality including: -Alternatively, run `dotnet new buildprops --use-artifacts` and the template will generate the *Directory.Build.props* file for you: +- You can [customize handling of members that aren't in the JSON payload.](../../standard/serialization/system-text-json/missing-members.md) +- gives you explicit control over when a `JsonSerializerOptions` instance is frozen. (You can also check it with the property.) +- is now obsolete. It's been superseded by the and properties. For more information, see [Chain source generators](#chain-source-generators). +- The new method, a variation of the existing method, returns `false` if no metadata for the specified type was found. +- Support for compiler-generated or *unspeakable* types in weakly typed source generation scenarios. Since compiler-generated types can't be explicitly specified by the source generator, now performs nearest-ancestor resolution at run time. This resolution determines the most appropriate supertype with which to serialize the value. -```xml - - - $(MSBuildThisFileDirectory)artifacts - - -``` +The following sections go into more depth about other serialization improvements: -By default, the common location is a folder named *artifacts* in the root of your repository rather than in each project folder. The folder structure under the root *artifacts* folder is as follows: +- [Source generator](#source-generator) +- [Interface hierarchies](#interface-hierarchies) +- [Naming policies](#naming-policies) +- [Read-only properties](#read-only-properties) +- [Disable reflection-based default](#disable-reflection-based-default) -```Directory -📁 artifacts - └──📂 - └──📂 - └──📂 -``` +For more information about JSON serialization in general, see [JSON serialization and deserialization in .NET](../../standard/serialization/system-text-json/overview.md). -The following table shows the default values for each level in the folder structure. The values, as well as the default location, can be overridden using properties in the *Directory.build.props* file. +### Source generator -| Folder level | Description | -|--|--| -| Type of output | Examples: `bin`, `obj`, `publish`, or `package` | -| Project name | Separates output by each project. | -| Pivot | Distinguishes between builds of a project for different configurations, target frameworks, and runtime identifiers. If multiple elements are needed, they're joined by an underscore (`_`). | +.NET 8 includes performance and reliability enhancements of the System.Text.Json [source generator](../../standard/serialization/system-text-json/source-generation.md) that are aimed at making the [native AOT](../../standard/glossary.md#native-aot) experience on par with the [reflection-based serializer](../../standard/serialization/system-text-json/source-generation-modes.md#overview). For example: -### `dotnet workload clean` command +- 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. +- Improved formatting of source-generated code. +- Additional diagnostics (such as `SYSLIB1034` and `SYSLIB1039`). +- Don't include types of ignored or inaccessible properties. +- Support for nesting `JsonSerializerContext` declarations within arbitrary type kinds. +- New converter type `JsonStringEnumConverter`. The existing class isn't supported in native AOT. You can annotate your enum types as follows: -.NET 8 introduces a new command to clean up workload packs that might be left over through several .NET SDK or Visual Studio updates. If you encounter issues when managing workloads, consider using `workload clean` to safely restore to a known state before trying again. The command has two modes: + ```csharp + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum MyEnum { Value1, Value2, Value3 } -- `dotnet workload clean` + [JsonSerializable(typeof(MyEnum))] + public partial class MyContext : JsonSerializerContext { } + ``` - Runs [workload garbage collection](https://github.com/dotnet/designs/blob/main/accepted/2021/workloads/workload-installation.md#workload-pack-installation-records-and-garbage-collection) for file-based or MSI-based workloads, which cleans up orphaned packs. Orphaned packs are from uninstalled versions of the .NET SDK or packs where installation records for the pack no longer exist. +- New `JsonConverter.Type` property lets you look up the type of a non-generic `JsonConverter`` instance: - If Visual Studio is installed, the command also lists any workloads that you should clean up manually using Visual Studio. + ```csharp + Dictionary CreateDictionary(IEnumerable converters) + => converters.Where(converter => converter.Type != null).ToDictionary(converter => converter.Type!); + ``` -- `dotnet workload clean --all` + The property is nullable since it returns `null` for `JsonConverterFactory` instances and `typeof(T)` for `JsonConverter` instances. - This mode is more aggressive and cleans every pack on the machine that's of the current SDK workload installation type (and that's not from Visual Studio). It also removes all workload installation records for the running .NET SDK feature band and below. +#### Chain source generators -### `dotnet publish` and `dotnet pack` assets +The class includes a new property that complements the existing property. These properties are used in contract customization for chaining source generators. The addition of the new property means that you don't have to specify all chained components at one call site—they can be added after the fact. -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. + also lets you introspect the chain or remove components from it. The following code snippet shows an example. -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`. +```csharp +var options = new JsonSerializerOptions +{ + TypeInfoResolver = JsonTypeInfoResolver.Combine( + ContextA.Default, ContextB.Default, ContextC.Default); +}; -```console -/app# dotnet new console -/app# dotnet build - app -> /app/bin/Debug/net8.0/app.dll -/app# dotnet publish - app -> /app/bin/Release/net8.0/app.dll - app -> /app/bin/Release/net8.0/publish/ -/app# dotnet publish -p:PublishRelease=false - app -> /app/bin/Debug/net8.0/app.dll - app -> /app/bin/Debug/net8.0/publish/ +options.TypeInfoResolverChain.Count; // 3 +options.TypeInfoResolverChain.RemoveAt(0); +options.TypeInfoResolverChain.Count; // 2 ``` -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). - -### `dotnet restore` security auditing - -Starting in .NET 8, you can opt into security checks for known vulnerabilities when dependency packages are restored. This auditing produces a report of security vulnerabilities with the affected package name, the severity of the vulnerability, and a link to the advisory for more details. When you run `dotnet add` or `dotnet restore`, warnings NU1901-NU1904 will appear for any vulnerabilities that are found. For more information, see [Audit for security vulnerabilities](../tools/dotnet-restore.md#audit-for-security-vulnerabilities). - -### Template engine - -The [template engine](https://github.com/dotnet/templating) provides a more secure experience in .NET 8 by integrating some of NuGet's security-related features. The improvements include: - -- Prevent downloading packages from `http://` feeds by default. For example, the following command will fail to install the template package because the source URL doesn't use HTTPS. - - `dotnet new install console --add-source "http://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json"` - - You can override this limitation by using the `--force` flag. - -- For `dotnet new`, `dotnet new install`, and `dotnet new update`, check for known vulnerabilities in the template package. If vulnerabilities are found and you wish to proceed, you must use the `--force` flag. - -- For `dotnet new`, provide information about the template package owner. Ownership is verified by the NuGet portal and can be considered a trustworthy characteristic. - -- For `dotnet search` and `dotnet uninstall`, indicate whether a template is installed from a package that's "trusted"—that is, it uses a [reserved prefix](/nuget/nuget-org/id-prefix-reservation). - -### Source Link - -[Source Link](../../standard/library-guidance/sourcelink.md) is now included in the .NET SDK. The goal is that by bundling Source Link into the SDK, instead of requiring a separate `` for the package, more packages will include this information by default. That information will improve the IDE experience for developers. - -### Source-build SDK - -The Linux distribution-built (source-build) SDK now has the capability to build self-contained applications using the source-build runtime packages. The distribution-specific runtime package is bundled with the source-build SDK. During self-contained deployment, this bundled runtime package will be referenced, thereby enabling the feature for users. - -## Serialization - -Many improvements have been made to serialization and deserialization functionality including: - -- 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](../../standard/glossary.md#native-aot) apps. -- 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. -- You can [customize handling of members that aren't in the JSON payload.](../../standard/serialization/system-text-json/missing-members.md) -- gives you explicit control over when a `JsonSerializerOptions` instance is frozen. (You can also check it with the property.) -- is now obsolete. It's been superseded by the and properties. For more information, see [Chain source generators](#chain-source-generators). -- The new method, a variation of the existing method, returns `false` if no metadata for the specified type was found. -- .NET 8 adds support for compiler-generated or *unspeakable* types in weakly typed source generation scenarios. Since compiler-generated types can't be explicitly specified by the source generator, now performs nearest-ancestor resolution at run time. This resolution determines the most appropriate supertype with which to serialize the value. - -The following sections go into more depth about other serialization improvements: - -- [Interface hierarchies](#interface-hierarchies) -- [Naming policies](#naming-policies) -- [Read-only properties](#read-only-properties) -- [Disable reflection-based default](#disable-reflection-based-default) -- [Chain source generators](#chain-source-generators) - -For more information about JSON serialization in general, see [JSON serialization and deserialization in .NET](../../standard/serialization/system-text-json/overview.md). - ### Interface hierarchies .NET 8 adds support for serializing properties from interface hierarchies. @@ -257,24 +187,6 @@ static JsonSerializerOptions GetDefaultOptions() } ``` -### Chain source generators - -The class includes a new property that complements the existing property. These properties are used in contract customization for chaining source generators. The addition of the new property means that you don't have to specify all chained components at one call site—they can be added after the fact. - - also lets you introspect the chain or remove components from it. The following code snippet shows an example. - -```csharp -var options = new JsonSerializerOptions -{ - TypeInfoResolver = JsonTypeInfoResolver.Combine( - ContextA.Default, ContextB.Default, ContextC.Default); -}; - -options.TypeInfoResolverChain.Count; // 3 -options.TypeInfoResolverChain.RemoveAt(0); -options.TypeInfoResolverChain.Count; // 2 -``` - ## Core .NET libraries This section contains the following subtopics: @@ -286,6 +198,8 @@ This section contains the following subtopics: - [System.Numerics and System.Runtime.Intrinsics](#systemnumerics-and-systemruntimeintrinsics) - [Data validation](#data-validation) - [Metrics](#metrics) +- [Cryptography](#cryptography) +- [Stream-based ZipFile methods](#stream-based-zipfile-methods) ### Time abstraction @@ -494,33 +408,114 @@ The new APIs include: - - -## Extension libraries +### Cryptography -### Metrics +.NET 8 adds support for the SHA-3 hashing primitives. (SHA-3 is currently supported by Linux with OpenSSL 1.1.1 or later and Windows 11 Build 25324 or later.) APIs where SHA-2 is available now offer a SHA-3 compliment. This includes `SHA3_256`, `SHA3_384`, and `SHA3_512` for hashing; `HMACSHA3_256`, `HMACSHA3_384`, and `HMACSHA3_512` for HMAC; `HashAlgorithmName.SHA3_256`, `HashAlgorithmName.SHA3_384`, and `HashAlgorithmName.SHA3_512` for hashing where the algorithm is configurable; and `RSAEncryptionPadding.OaepSHA3_256`, `RSAEncryptionPadding.OaepSHA3_384`, and `RSAEncryptionPadding.OaepSHA3_512` for RSA OAEP encryption. -You can register the new interface in dependency injection (DI) containers and use it to create objects in an isolated manner. +The following example shows how to use the APIs, including the `SHA3_256.IsSupported` property to determine if the platform supports SHA-3. -Register the to the DI container using the default meter factory implementation: +```csharp +// Hashing example +if (SHA3_256.IsSupported) +{ + byte[] hash = SHA3_256.HashData(dataToHash); +} +else +{ + // ... +} + +// Signing example +if (SHA3_256.IsSupported) +{ + using ECDsa ec = ECDsa.Create(ECCurve.NamedCurves.nistP256); + byte[] signature = ec.SignData(dataToBeSigned, HashAlgorithmName.SHA3_256); +} +else +{ + // ... +} +``` + +SHA-3 support is currently aimed at supporting cryptographic primitives. Higher-level constructions and protocols aren't expected to fully support SHA-3 initially. These protocols include X.509 certificates, , and COSE. + +### Stream-based ZipFile methods + +.NET 8 includes new overloads of that allow you to collect all the files included in a directory and zip them, then store the resulting zip file into the provided stream. Similarly, new overloads let you provide a stream containing a zipped file and extract its contents into the filesystem. These are the new overloads: ```csharp -// 'services' is the DI IServiceCollection. -services.AddMetrics(); +namespace System.IO.Compression; + +public static partial class ZipFile +{ + public static void CreateFromDirectory(string sourceDirectoryName, Stream destination); + public static void CreateFromDirectory(string sourceDirectoryName, Stream destination, CompressionLevel compressionLevel, bool includeBaseDirectory); + public static void CreateFromDirectory(string sourceDirectoryName, Stream destination, CompressionLevel compressionLevel, bool includeBaseDirectory, Encoding? entryNameEncoding); + + public static void ExtractToDirectory(Stream source, string destinationDirectoryName) { } + public static void ExtractToDirectory(Stream source, string destinationDirectoryName, bool overwriteFiles) { } + public static void ExtractToDirectory(Stream source, string destinationDirectoryName, Encoding? entryNameEncoding) { } + public static void ExtractToDirectory(Stream source, string destinationDirectoryName, Encoding? entryNameEncoding, bool overwriteFiles) { } +} ``` -Consumers can then obtain the meter factory and use it to create a new object. +These new APIs can be useful when disk space is constrained, because they avoid having to use the disk as an intermediate step. + +## Extension libraries + +This section contains the following subtopics: + +- [Options validation](#options-validation) +- [LoggerMessageAttribute constructors](#loggermessageattribute-constructors) +- [Extensions metrics](#extensions-metrics) + +### Options validation + +#### Source generator + +To reduce startup overhead and improve validation feature set, we've introduced a source code generator that implements the validation logic. The following code shows example models and validator classes. ```csharp -IMeterFactory meterFactory = serviceProvider.GetRequiredService(); +public class FirstModelNoNamespace +{ + [Required] + [MinLength(5)] + public string P1 { get; set; } = string.Empty; -MeterOptions options = new MeterOptions("MeterName") + [Microsoft.Extensions.Options.ValidateObjectMembers(typeof(SecondValidatorNoNamespace))] + public SecondModelNoNamespace? P2 { get; set; } +} + +public class SecondModelNoNamespace { - Version = "version", -}; + [Required] + [MinLength(5)] + public string P4 { get; set; } = string. Empty; +} -Meter meter = meterFactory.Create(options); +[OptionsValidator] +public partial class FirstValidatorNoNamespace : IValidateOptions +{ +} + +[OptionsValidator] +public partial class SecondValidatorNoNamespace : IValidateOptions +{ +} ``` -### ValidateOptionsResultBuilder type +If your app uses dependency injection, you can inject the validation as shown in the following example code. + +```csharp +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddControllersWithViews(); +builder.Services.Configure(builder.Configuration.GetSection(...)); + +builder.Services.AddSingleton, FirstValidatorNoNamespace>(); +builder.Services.AddSingleton, SecondValidatorNoNamespace>(); +``` + +#### ValidateOptionsResultBuilder type .NET 8 introduces the type to facilitate the creation of a object. Importantly, this builder allows for the accumulation of multiple errors. Previously, creating the object that's required to implement was difficult and sometimes resulted in layered validation errors. If there were multiple errors, the validation process often stopped at the first error. @@ -539,6 +534,72 @@ ValidateOptionsResult result = builder.Build(); builder.Clear(); ``` +### LoggerMessageAttribute constructors + + now offers additional constructor overloads. Previously, you had to choose either the parameterless constructor or the constructor that required all of the parameters (event ID, log level, and message). The new overloads offer greater flexibility in specifying the required parameters with reduced code. If you don't supply an event ID, the system generates one automatically. + +```csharp +public LoggerMessageAttribute(LogLevel level, string message); +public LoggerMessageAttribute(LogLevel level); +public LoggerMessageAttribute(string message); +``` + +### Extensions metrics + +#### IMeterFactory interface + +You can register the new interface in dependency injection (DI) containers and use it to create objects in an isolated manner. + +Register the to the DI container using the default meter factory implementation: + +```csharp +// 'services' is the DI IServiceCollection. +services.AddMetrics(); +``` + +Consumers can then obtain the meter factory and use it to create a new object. + +```csharp +IMeterFactory meterFactory = serviceProvider.GetRequiredService(); + +MeterOptions options = new MeterOptions("MeterName") +{ + Version = "version", +}; + +Meter meter = meterFactory.Create(options); +``` + +#### MetricCollector\ class + +The new class lets you record metric measurements along with timestamps. Additionally, the class offers the flexibility to use a time provider of your choice for accurate timestamp generation. + +```csharp +const string CounterName = "MyCounter"; + +var now = DateTimeOffset.Now; + +var timeProvider = new FakeTimeProvider(now); +using var meter = new Meter(Guid.NewGuid().ToString()); +var counter = meter.CreateCounter(CounterName); +using var collector = new MetricCollector(counter, timeProvider); + +Assert.Empty(collector.GetMeasurementSnapshot()); +Assert.Null(collector.LastMeasurement); + +counter. Add(3); + +// Verify the update was recorded. +Assert.Equal(counter, collector.Instrument); +Assert.NotNull(collector.LastMeasurement); + +Assert.Single(collector.GetMeasurementSnapshot()); +Assert.Same(collector.GetMeasurementSnapshot().Last(), collector.LastMeasurement); +Assert.Equal(3, collector.LastMeasurement.Value); +Assert.Empty(collector.LastMeasurement.Tags); +Assert.Equal(now, collector.LastMeasurement.Timestamp); +``` + ## Garbage collection .NET 8 adds a capability to adjust the memory limit on the fly. This is useful in cloud-service scenarios, where demand comes and goes. To be cost-effective, services should scale up and down on resource consumption as the demand fluctuates. When a service detects a decrease in demand, it can scale down resource consumption by reducing its memory limit. Previously, this would fail because the garbage collector (GC) was unaware of the change and might allocate more memory than the new limit. With this change, you can call the `_RefreshMemoryLimit` API to update the GC with the new memory limit. @@ -571,20 +632,18 @@ refreshMemoryLimitMethod.Invoke(null, Array.Empty); ## Configuration-binding source generator -[ASP.NET Core uses configuration providers](/aspnet/core/fundamentals/configuration/) to perform app configuration. The providers read key-value pair data from different sources, such as settings files, environment variables, and Azure Key Vault. is the type that maps configuration values to strongly typed objects. Previously, the mapping was performed using reflection, which can cause issues for trimming and Native AOT. Starting in .NET 8, you can opt into the use of a source generator to generate the binding implementations. The generator probes for , , and calls to retrieve type info from. When the generator is enabled in a project, the compiler implicitly chooses generated methods over the pre-existing reflection-based framework implementations. +.NET 8 introduces a source generator to provide AOT and trim-friendly [configuration](/aspnet/core/fundamentals/configuration/) in ASP.NET Core. The generator is an alternative to the pre-existing reflection-based implementation. -To opt into the source generator, set the `EnableMicrosoftExtensionsConfigurationBinderSourceGenerator` property to `true` in your project file: +The source generator probes for , , and calls to retrieve type info from. When the generator is enabled in a project, the compiler implicitly chooses generated methods over the pre-existing reflection-based framework implementations. + +No source code changes are needed to use the generator. It's enabled by default in AOT'd web apps. For other project types, the source generator is off by default, but you can opt in by setting the `EnableConfigurationBindingGenerator` property to `true` in your project file: ```xml - - true - + true ``` -You'll also need to download the latest preview version of the [Microsoft.Extensions.Configuration.Binder NuGet package](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Binder). - The following code shows an example of invoking the binder. ```csharp @@ -714,6 +773,42 @@ The default console app template now includes support for AOT out-of-the-box. To - Enables compatibility analyzers for trimming, AOT, and single file. These analyzers alert you to potentially problematic parts of your project (if there are any). - Enables debug-time emulation of AOT so that when you debug your project without AOT compilation, you get a similar experience to AOT. For example, if you use in a NuGet package that wasn't annotated for AOT (and therefore was missed by the compatibility analyzer), the emulation means you won't have any surprises when you try to publish the project with AOT. +### Target iOS-like platforms with native AOT + +.NET 8 starts the work to enable native AOT support for iOS-like platforms. You can now build and run .NET iOS and .NET MAUI applications with native AOT on the following platforms: + +- `ios` +- `iossimulator` +- `maccatalyst` +- `tvos` +- `tvossimulator` + +Preliminary testing shows that app size on disk decreases by about 40% for .NET iOS apps that use native AOT instead of Mono. App size on disk for .NET MAUI iOS apps *increases* by about 25%. However, since the .NET 8 support is only the first step for the feature as a whole, we urge you not to draw conclusions about performance at this point. + +Native AOT support is available as an opt-in feature intended for app deployment; Mono is still the default runtime for app development and deployment. To build and run a .NET MAUI application with native AOT on an iOS device, use `dotnet workload install maui` to install the .NET MAUI workload and `dotnet new maui -n HelloMaui` to create the app. Then, set the MSBuild properties `PublishAot` and `PublishAotUsingRuntimePack` to `true` in the project file. + +```xml + + true + true + +``` + +When you set these properties and run `dotnet publish` as shown in the following example, the app will be deployed by using native AOT. + +```dotnetcli +dotnet publish -f net8.0-ios -c Release -r ios-arm64 /t:Run +``` + +#### Limitations + +Not all iOS features are compatible with native AOT. Similarly, not all libraries commonly used in iOS are compatible with NativeAOT. And in addition to the existing [limitations of native AOT deployment](../deploying/native-aot/index.md#limitations-of-native-aot-deployment), the following list shows some of the other limitations when targeting iOS-like platforms: + +- Installation and app deployment using Visual Studio is untested. +- Using native AOT is only enabled during app deployment (`dotnet publish`). +- library functionality isn't fully supported. +- Managed code debugging is only supported with Mono. + ## Performance improvements .NET 8 includes improvements to code generation and just-in time (JIT) compilation: @@ -732,7 +827,126 @@ In addition, dynamic profile-guided optimization (PGO) has been improved and is On average, dynamic PGO increases performance by about 15%. In a benchmark suite of ~4600 tests, 23% saw performance improvements of 20% or more. -## .NET container images +## .NET SDK changes + +This section contains the following subtopics: + +- [Terminal build output](#terminal-build-output) +- [Simplified output paths](#simplified-output-paths) +- ['dotnet workload clean' command](#dotnet-workload-clean-command) +- ['dotnet publish' and 'dotnet pack' assets](#dotnet-publish-and-dotnet-pack-assets) +- [Template engine](#template-engine) +- [Source Link](#source-link) +- [Source-build SDK](#source-build-sdk) + +### Terminal build output + +`dotnet build` has a new option to produce more modernized build output. This *terminal logger* output groups errors with the project they came from, better differentiates the different target frameworks for multi-targeted projects, and provides real-time information about what the build is doing. To opt into the new output, use the `--tl` option. For more information about this option, see [dotnet build options](../tools/dotnet-build.md#options). + +### Simplified output paths + +.NET 8 introduces an option to simplify the output path and folder structure for build outputs. Previously, .NET apps produced a deep and complex set of output paths for different build artifacts. The new, simplified output path structure gathers all build outputs into a common location, which makes it easier for tooling to anticipate. + +To opt into the new output path format, use one of the following properties in your *Directory.Build.props* file: + +- Add an `ArtifactsPath` property with a value of `$(MSBuildThisFileDirectory)artifacts` (or whatever you want the folder location to be), OR +- To use the default location, simply set the `UseArtifactsOutput` property to `true`. + +Alternatively, run `dotnet new buildprops --use-artifacts` and the template will generate the *Directory.Build.props* file for you: + +```xml + + + $(MSBuildThisFileDirectory)artifacts + + +``` + +By default, the common location is a folder named *artifacts* in the root of your repository rather than in each project folder. The folder structure under the root *artifacts* folder is as follows: + +```Directory +📁 artifacts + └──📂 + └──📂 + └──📂 +``` + +The following table shows the default values for each level in the folder structure. The values, as well as the default location, can be overridden using properties in the *Directory.build.props* file. + +| Folder level | Description | +|--|--| +| Type of output | Examples: `bin`, `obj`, `publish`, or `package` | +| Project name | Separates output by each project. | +| Pivot | Distinguishes between builds of a project for different configurations, target frameworks, and runtime identifiers. If multiple elements are needed, they're joined by an underscore (`_`). | + +### `dotnet workload clean` command + +.NET 8 introduces a new command to clean up workload packs that might be left over through several .NET SDK or Visual Studio updates. If you encounter issues when managing workloads, consider using `workload clean` to safely restore to a known state before trying again. The command has two modes: + +- `dotnet workload clean` + + Runs [workload garbage collection](https://github.com/dotnet/designs/blob/main/accepted/2021/workloads/workload-installation.md#workload-pack-installation-records-and-garbage-collection) for file-based or MSI-based workloads, which cleans up orphaned packs. Orphaned packs are from uninstalled versions of the .NET SDK or packs where installation records for the pack no longer exist. + + If Visual Studio is installed, the command also lists any workloads that you should clean up manually using Visual Studio. + +- `dotnet workload clean --all` + + This mode is more aggressive and cleans every pack on the machine that's of the current SDK workload installation type (and that's not from Visual Studio). It also removes all workload installation records for the running .NET SDK feature band and below. + +### `dotnet publish` and `dotnet pack` assets + +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. + +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`. + +```console +/app# dotnet new console +/app# dotnet build + app -> /app/bin/Debug/net8.0/app.dll +/app# dotnet publish + app -> /app/bin/Release/net8.0/app.dll + app -> /app/bin/Release/net8.0/publish/ +/app# dotnet publish -p:PublishRelease=false + app -> /app/bin/Debug/net8.0/app.dll + app -> /app/bin/Debug/net8.0/publish/ +``` + +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). + +### `dotnet restore` security auditing + +Starting in .NET 8, you can opt into security checks for known vulnerabilities when dependency packages are restored. This auditing produces a report of security vulnerabilities with the affected package name, the severity of the vulnerability, and a link to the advisory for more details. When you run `dotnet add` or `dotnet restore`, warnings NU1901-NU1904 will appear for any vulnerabilities that are found. For more information, see [Audit for security vulnerabilities](../tools/dotnet-restore.md#audit-for-security-vulnerabilities). + +### Template engine + +The [template engine](https://github.com/dotnet/templating) provides a more secure experience in .NET 8 by integrating some of NuGet's security-related features. The improvements include: + +- Prevent downloading packages from `http://` feeds by default. For example, the following command will fail to install the template package because the source URL doesn't use HTTPS. + + `dotnet new install console --add-source "http://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json"` + + You can override this limitation by using the `--force` flag. + +- For `dotnet new`, `dotnet new install`, and `dotnet new update`, check for known vulnerabilities in the template package. If vulnerabilities are found and you wish to proceed, you must use the `--force` flag. + +- For `dotnet new`, provide information about the template package owner. Ownership is verified by the NuGet portal and can be considered a trustworthy characteristic. + +- For `dotnet search` and `dotnet uninstall`, indicate whether a template is installed from a package that's "trusted"—that is, it uses a [reserved prefix](/nuget/nuget-org/id-prefix-reservation). + +### Source Link + +[Source Link](../../standard/library-guidance/sourcelink.md) is now included in the .NET SDK. The goal is that by bundling Source Link into the SDK, instead of requiring a separate `` for the package, more packages will include this information by default. That information will improve the IDE experience for developers. + +### Source-build SDK + +The Linux distribution-built (source-build) SDK now has the capability to build self-contained applications using the source-build runtime packages. The distribution-specific runtime package is bundled with the source-build SDK. During self-contained deployment, this bundled runtime package will be referenced, thereby enabling the feature for users. + +## Containers + +- [Container images](#container-images) +- [Containers performance and compatibility](#container-performance-and-compatibility) + +### Container images The following changes have been made to .NET container images for .NET 8: @@ -743,11 +957,11 @@ The following changes have been made to .NET container images for .NET 8: - [Build multi-platform container images](#build-multi-platform-container-images) - [Alpine ASP.NET Docker composite images](#alpine-aspnet-docker-composite-images) -### Debian 12 +#### Debian 12 The container images now use [Debian 12 (Bookworm)](https://wiki.debian.org/DebianBookworm). Debian is the default Linux distro in the .NET container images. -### Non-root user +#### Non-root user 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): @@ -759,7 +973,7 @@ USER app 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`. -### Preview images +#### Preview images 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: @@ -767,11 +981,11 @@ Preview container images tags now have a `-preview` suffix instead of just using The `-preview` suffix will be removed for release candidate (RC) releases. -### Chiseled Ubuntu images +#### Chiseled Ubuntu images [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). -### Build multi-platform container images +#### Build multi-platform container images Docker supports using and building [multi-platform images](https://docs.docker.com/build/building/multi-platform/) that work across multiple environments. .NET 8 introduces a new pattern that enables you to mix and match architectures with the .NET images you build. As an example, if you're using macOS and want to target an x64 cloud service in Azure, you can build the image by using the `--platform` switch as follows: @@ -789,12 +1003,63 @@ RUN dotnet publish -a $TARGETARCH --self-contained false --no-restore -o /app For more information, see the [Improving multi-platform container support](https://devblogs.microsoft.com/dotnet/improving-multiplatform-container-support/) blog post. -### Alpine ASP.NET Docker composite images +#### Alpine ASP.NET Docker composite images As part of an effort to improve containerization performance, a new ASP.NET Alpine-based Docker image with a composite version of the runtime is available. This composite is built by compiling multiple MSIL assemblies into a single ready-to-run (R2R) output binary. Because these assemblies are embedded into a single image, jitting takes less time, and the startup performance of apps improves. The other big advantage of the composite over the regular ASP.NET image is that the composite images have a smaller size on disk. There is a caveat to be aware of. Since composites have multiple assemblies embedded into one, they have tighter version coupling. Apps can't use custom versions of framework or ASP.NET binaries. +### Container performance and compatibility + +.NET 8 has improved performance for pushing containers to remote registries, especially Azure registries. Speedup comes from pushing layers in one operation and, for registries that don't support atomic uploads, a more reliable chunking mechanism. + +These improvements also mean that more registries are supported: Harbor, Artifactory, Quay.io, and Podman. + +Some generated-image defaults have also changed: + +- The new [`non-root` capability](#non-root-user) of the Microsoft .NET containers is now the default, which helps your apps stay secure-by-default. Change this default at any time by setting your own `ContainerUser``. +- The default container tag is now `latest`. This default is in line with other tooling in the containers space and makes containers easier to use in inner development loops. + +## Source-generated COM interop + +.NET 8 includes a new source generator that supports interoperating with COM interfaces. You can use the to mark an interface as a COM interface for the source generator. The source generator will then generate code to enable calling from C# code to unmanaged code. It also generates code to enable calling from unmanaged code into C#. This source generator integrates with , and you can use types with the as parameters and return types in `LibraryImport`-attributed methods. + +```csharp +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +[GeneratedComInterface] +[Guid("5401c312-ab23-4dd3-aa40-3cb4b3a4683e")] +interface IComInterface +{ + void DoWork(); +} + +internal class MyNativeLib +{ + [LibraryImport(nameof(MyNativeLib))] + public static partial void GetComInterface(out IComInterface comInterface); +} +``` + +The source generator also supports the new attribute to enable you to pass types that implement interfaces with the attribute to unmanaged code. The source generator will generate the code necessary to expose a COM object that implements the interfaces and forwards calls to the managed implementation. + +Methods on interfaces with the attribute support all the same types as `LibraryImportAttribute`, and `LibraryImportAttribute` now supports `GeneratedComInterface`-attributed types and `GeneratedComClass`-attributed types. + +If your C# code only uses a `GeneratedComInterface`-attributed interface to either wrap a COM object from unmanaged code or wrap a managed object from C# to expose to unmanaged code, you can use the options in the property to customize which code will be generated. These options means you don't need to write marshallers for scenarios that you know won't be used. + +The source generator uses the new type to create and manage the COM object wrappers and the managed object wrappers. This new type handles providing the expected .NET user experience for COM interop, while providing customization points for advanced users. If your application has its own mechanism for defining types from COM or if you need to support scenarios that source-generated COM doesn't currently support, consider using the new type to add the missing features for your scenario and get the same .NET user experience for your COM types. + +If you're using Visual Studio, new analyzers and code fixes make it easy to convert your existing COM interop code to use source-generated interop. Next to each interface that has the , a lightbulb offers an option to convert to source-generated interop. The fix changes the interface to use the attribute. And next to every class that implements an interface with `GeneratedComInterfaceAttribute`, a lightbulb offers an option to add the attribute to the type. Once your types are converted, you can move your `DllImport` methods to use `LibraryImportAttribute`. + +### Limitations + +The COM source generator doesn't support apartment affinity, using the `new` keyword to activate a COM CoClass, and the following APIs: + +- -based interfaces. +- -based interfaces. +- COM properties and events. + ## .NET on Linux ### Minimum support baselines for Linux @@ -838,10 +1103,16 @@ You can opt out of verification by setting the environment variable `DOTNET_NUGE ### .NET blog +- [Announcing .NET 8 Preview 6](https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-6/) +- [Announcing .NET 8 Preview 5](https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-5/) - [Announcing .NET 8 Preview 4](https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-4/) - [Announcing .NET 8 Preview 3](https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-3/) - [Announcing .NET 8 Preview 2](https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-2/) - [Announcing .NET 8 Preview 1](https://devblogs.microsoft.com/dotnet/announcing-dotnet-8-preview-1/) + +- [ASP.NET Core updates in .NET 8 Preview 6](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-8-preview-6/) +- [ASP.NET Core updates in .NET 8 Preview 5](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-8-preview-5/) +- [ASP.NET Core updates in .NET 8 Preview 4](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-8-preview-4/) - [ASP.NET Core updates in .NET 8 Preview 3](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-8-preview-3/) - [ASP.NET Core updates in .NET 8 Preview 2](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-8-preview-2/) - [ASP.NET Core updates in .NET 8 Preview 1](https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-8-preview-1/)