Skip to content

Commit

Permalink
What's new for .NET 9 RC 1 (#42550)
Browse files Browse the repository at this point in the history
  • Loading branch information
gewarren committed Sep 10, 2024
1 parent b3ec504 commit 17d020b
Show file tree
Hide file tree
Showing 13 changed files with 301 additions and 60 deletions.
147 changes: 111 additions & 36 deletions docs/core/whats-new/dotnet-9/libraries.md

Large diffs are not rendered by default.

18 changes: 13 additions & 5 deletions docs/core/whats-new/dotnet-9/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
title: What's new in .NET 9
description: Learn about the new .NET features introduced in .NET 9 for the runtime, libraries, and SDK. Also find links to what's new in other areas, such as ASP.NET Core.
titleSuffix: ""
ms.date: 08/15/2024
ms.date: 09/10/2024
ms.topic: whats-new
---

# What's new in .NET 9

Learn about the new features in .NET 9 and find links to further documentation.
Expand All @@ -17,7 +18,7 @@ New for .NET 9, the engineering team posts .NET 9 preview updates on [GitHub Dis

The .NET 9 runtime includes a new attribute model for feature switches with trimming support. The new attributes make it possible to define [feature switches](https://github.com/dotnet/designs/blob/main/accepted/2020/feature-switch.md) that libraries can use to toggle areas of functionality.

Garbage collection includes a *dynamic adaptation to application size* feature that's used by default instead of Server GC.
Garbage collection includes a _dynamic adaptation to application size_ feature that's used by default instead of Server GC.

The runtime also includes numerous performance improvements, including loop optimizations, inlining, and Arm64 vectorization and code generation.

Expand All @@ -29,19 +30,26 @@ For more information, see [What's new in the .NET 9 runtime](runtime.md).

In LINQ, the new methods <xref:System.Linq.Enumerable.CountBy%2A> and <xref:System.Linq.Enumerable.AggregateBy%2A> make it possible to aggregate state by key without needing to allocate intermediate groupings via <xref:System.Linq.Enumerable.GroupBy%2A>.

For collection types, the <xref:System.Collections.Generic.PriorityQueue%602?displayProperty=fullName> type includes a new <xref:System.Collections.Generic.PriorityQueue%602.Remove(%600,%600@,%601@,System.Collections.Generic.IEqualityComparer{%600})> method that you can use to *update* the priority of an item in the queue.
For collection types, the <xref:System.Collections.Generic.PriorityQueue%602?displayProperty=fullName> type includes a new <xref:System.Collections.Generic.PriorityQueue%602.Remove(%600,%600@,%601@,System.Collections.Generic.IEqualityComparer{%600})> method that you can use to _update_ the priority of an item in the queue.

For cryptography, .NET 9 adds a new one-shot hash method on the <xref:System.Security.Cryptography.CryptographicOperations> type. It also adds new classes that use the KMAC algorithm.

For reflection, the new <xref:System.Reflection.Emit.PersistedAssemblyBuilder> type lets you *save* an emitted assembly. This new class also includes PDB support, meaning you can emit symbol info and use it to debug a generated assembly.
For reflection, the new <xref:System.Reflection.Emit.PersistedAssemblyBuilder> type lets you _save_ an emitted assembly. This new class also includes PDB support, meaning you can emit symbol info and use it to debug a generated assembly.

The <xref:System.TimeSpan> class includes new `From*` methods that let you create a `TimeSpan` object from an `int` (instead of a `double`). These methods help to avoid errors caused by inherent imprecision in floating-point calculations.

For more information, see [What's new in the .NET 9 libraries](libraries.md).

## .NET SDK

The .NET 9 SDK introduces *workload sets*, where all of your workloads stay at a single, specific version until explicitly updated. Unit testing has better MSBuild integration that allows you to run tests in parallel. For tools, a new option for [`dotnet tool install`](../../tools/dotnet-tool-install.md) lets users (instead of tool authors) decide whether a tool is allowed to run on a newer .NET runtime version than the version the tool targets. NuGet security audits run on both direct and transitive package references, by default. The terminal logger is now enabled by default and also has improved usability. For example, the total count of failures and warnings is now summarized at the end of a build. New MSBuild script analyzers are available. The SDK can detect and adjust for version mismatches between the .NET SDK and MSBuild.
The .NET 9 SDK introduces _workload sets_, where all of your workloads stay at a single, specific version until explicitly updated. For tools, a new option for [`dotnet tool install`](../../tools/dotnet-tool-install.md) lets users (instead of tool authors) decide whether a tool is allowed to run on a newer .NET runtime version than the version the tool targets. In addition:

- Unit testing has better MSBuild integration that allows you to run tests in parallel.
- NuGet security audits run on both direct and transitive package references, by default.
- The terminal logger is enabled by default and also has improved usability. For example, the total count of failures and warnings is now summarized at the end of a build.
- New MSBuild script analyzers ("build checks") are available.
- The SDK can detect and adjust for version mismatches between the .NET SDK and MSBuild.
- The `dotnet workload history` command shows you the history of workload installations and modifications for the current .NET SDK installation.

For more information, see [What's new in the SDK for .NET 9](sdk.md).

Expand Down
2 changes: 1 addition & 1 deletion docs/core/whats-new/dotnet-9/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: What's new in .NET 9 runtime
description: Learn about the new .NET features introduced in the .NET 9 runtime.
titleSuffix: ""
ms.date: 08/08/2024
ms.date: 09/09/2024
ms.topic: whats-new
---
# What's new in the .NET 9 runtime
Expand Down
36 changes: 27 additions & 9 deletions docs/core/whats-new/dotnet-9/sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
title: What's new in the SDK for .NET 9
description: Learn about the new .NET SDK features introduced in .NET 9, including for unit testing, terminal logger, tool roll-forward, and build script analyzers.
titleSuffix: ""
ms.date: 08/15/2024
ms.date: 09/09/2024
ms.topic: whats-new
---

# What's new in the SDK for .NET 9

This article describes new features in the .NET SDK for .NET 9. It's been updated for .NET 9 Preview 7.
This article describes new features in the .NET SDK for .NET 9. It's been updated for .NET RC 1.

## Unit testing

Expand All @@ -19,15 +20,15 @@ In .NET 9, `dotnet test` is more fully integrated with MSBuild. Because MSBuild

### Terminal logger test display

Test result reporting for [`dotnet test`](../../tools/dotnet-test.md) is now supported directly in the MSBuild terminal logger. You get more fully featured test reporting both *while* tests are running (displays the running test name) and *after* tests are completed (any test errors are rendered in a better way).
Test result reporting for [`dotnet test`](../../tools/dotnet-test.md) is now supported directly in the MSBuild terminal logger. You get more fully featured test reporting both _while_ tests are running (displays the running test name) and _after_ tests are completed (any test errors are rendered in a better way).

For more information about the terminal logger, see [dotnet build options](../../tools/dotnet-build.md#options).

## .NET tool roll-forward

[.NET tools](../../tools/global-tools.md) are framework-dependent apps that you can install globally or locally, then run using the .NET SDK and installed .NET runtimes. These tools, like all .NET apps, target a specific major version of .NET. By default, apps don't run on *newer* versions of .NET. Tool authors have been able to opt in to running their tools on newer versions of the .NET runtime by setting the `RollForward` MSBuild property. However, not all tools do so.
[.NET tools](../../tools/global-tools.md) are framework-dependent apps that you can install globally or locally, then run using the .NET SDK and installed .NET runtimes. These tools, like all .NET apps, target a specific major version of .NET. By default, apps don't run on _newer_ versions of .NET. Tool authors have been able to opt in to running their tools on newer versions of the .NET runtime by setting the `RollForward` MSBuild property. However, not all tools do so.

A new option for [`dotnet tool install`](../../tools/dotnet-tool-install.md) lets *users* decide how .NET tools should be run. When you install a tool via `dotnet tool install`, or when you run tool via [`dotnet tool run <toolname>`](../../tools/dotnet-tool-run.md), you can specify a new flag called `--allow-roll-forward`. This option configures the tool with roll-forward mode `Major`. This mode allows the tool to run on a newer major version of .NET if the matching .NET version is not available. This feature helps early adopters use .NET tools without tool authors having to change any code.
A new option for [`dotnet tool install`](../../tools/dotnet-tool-install.md) lets _users_ decide how .NET tools should be run. When you install a tool via `dotnet tool install`, or when you run tool via [`dotnet tool run <toolname>`](../../tools/dotnet-tool-run.md), you can specify a new flag called `--allow-roll-forward`. This option configures the tool with roll-forward mode `Major`. This mode allows the tool to run on a newer major version of .NET if the matching .NET version is not available. This feature helps early adopters use .NET tools without tool authors having to change any code.

## Terminal logger

Expand Down Expand Up @@ -77,7 +78,7 @@ Consider the following project file that emits a warning when the project is bui
</Project>
```

When you run `dotnet build -tl` on the .NET 8 SDK, the output is as shown following this paragraph. Each line of the multi-line warning is a separate line with a full error message prefix in the output, which is hard to read. Also, the final build summary says that there *were* warnings, but not *how many* there were. The missing information can make it hard to determine if a particular build is better or worse than previous builds.
When you run `dotnet build -tl` on the .NET 8 SDK, the output is as shown following this paragraph. Each line of the multi-line warning is a separate line with a full error message prefix in the output, which is hard to read. Also, the final build summary says that there _were_ warnings, but not _how many_ there were. The missing information can make it hard to determine if a particular build is better or worse than previous builds.

```terminal
$ dotnet build -tl
Expand Down Expand Up @@ -112,7 +113,7 @@ If you have feedback about the terminal logger, you can provide it in the [MSBui

## NuGet security audits

Starting in .NET 8, `dotnet restore` [audits NuGet package references for known vulnerabilities](../../tools/dotnet-restore.md#audit-for-security-vulnerabilities). In .NET 9, the default mode has changed from auditing only *direct* package references to auditing both *direct* and *transitive* package references.
Starting in .NET 8, `dotnet restore` [audits NuGet package references for known vulnerabilities](../../tools/dotnet-restore.md#audit-for-security-vulnerabilities). In .NET 9, the default mode has changed from auditing only _direct_ package references to auditing both _direct_ and _transitive_ package references.

## MSBuild script analyzers ("BuildChecks")

Expand All @@ -128,15 +129,15 @@ For more information, see the [design documentation](https://github.com/dotnet/m

Many users install the .NET SDK and Visual Studio at different cadences. While this flexibility is desirable, it can lead to problems for tooling that needs to interop between the two environments. One example of this kind of tooling is Roslyn Analyzers. Analyzer authors have to code for specific versions of Roslyn, but which versions are available and which is used by a given build is sometimes unclear.

This kind of version mismatch between the .NET SDK and MSBuild is referred to as a *torn SDK*. When you're in this state, you might see errors like this:
This kind of version mismatch between the .NET SDK and MSBuild is referred to as a _torn SDK_. When you're in this state, you might see errors like this:

> CSC : warning CS9057: The analyzer assembly '..\dotnet\sdk\8.0.200\Sdks\Microsoft.NET.Sdk.Razor\source-generators\Microsoft.CodeAnalysis.Razor.Compiler.SourceGenerators.dll' references version '4.9.0.0' of the compiler, which is newer than the currently running version '4.8.0.0'.
.NET 9 can detect and automatically adjust for this problem scenario. The SDK's MSBuild logic embeds the version of MSBuild it shipped with, and that information can be used to detect when the SDK is running in an environment with a different version. When that happens, the SDK inserts an implicit download of a support package called Microsoft.Net.Sdk.Compilers.Toolset that ensures a consistent analyzer experience.

## Workload sets

*Workload sets* is an SDK feature intended to give users more control over the workloads they install and the cadence of change of those workloads. In previous versions, workloads were periodically updated as new versions of individual workloads were released onto any configured NuGet feeds. Now, *all* of your workloads stay at a specific, single version until you make an explicit update gesture.
_Workload sets_ is an SDK feature intended to give users more control over the workloads they install and the cadence of change of those workloads. In previous versions, workloads were periodically updated as new versions of individual workloads were released onto any configured NuGet feeds. Now, _all_ of your workloads stay at a specific, single version until you make an explicit update gesture.

You can see what mode your SDK installation is in by running `dotnet workload --info`:

Expand All @@ -162,6 +163,23 @@ If you need to change back for any reason, you can run the same command with `ma

For more information, see [.NET SDK workload sets](../../tools/dotnet-workload-sets.md).

## Workload history

.NET SDK workloads are an integral part of .NET MAUI and Blazor WebAssembly. In their default configuration, you can update workloads independently as .NET tooling authors release new versions. In addition, .NET SDK installations done through Visual Studio install a parallel set of versions. Without taking care, the workload installation status of a given .NET SDK installation can drift over time, but there hasn't been a way to visualize this drift.

To address this, .NET 9 adds a new `dotnet workload history` command to the .NET SDK. `dotnet workload history` prints out a table of the history of workload installations and modifications for the current .NET SDK installation. The table shows the date of the installation or modification, the command that was run, the workloads that were installed or modified, and the relevant versions for the command. This output can help you understand the drift in workload installations over time, and help you make informed decisions about which workloads versions to set your installation to. You can think of it as `git reflog` for workloads.

```dotnetcli
> dotnet workload history
Id Date Command Workloads Global.json Version Workload Version
-----------------------------------------------------------------------------------------------------------------------------------------------
1 1/1/0001 12:00:00 AM +00:00 InitialState android, ios, maccatalyst, maui-windows 9.0.100-manifests.6d3c8f5d
2 9/4/2024 8:15:33 PM -05:00 install android, aspire, ios, maccatalyst, maui-windows 9.0.100-rc.1.24453.3
```

In this example, the SDK was initially installed with the `android`, `ios`, `maccatalyst`, and `maui-windows` workloads. Then, the `dotnet workload install aspire --version 9.0.100-rc.1.24453.3` command was used to install the `aspire` workload and switch to [workload sets mode](../../tools/dotnet-workload-sets.md). To return to the previous state, you can use the ID from the first column in the history table, for example, `dotnet workload update --from-history 1`.

## Containers

- [Publishing support for insecure registries](#publishing-support-for-insecure-registries)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ private static Dictionary<string, int> CountWords(ReadOnlySpan<char> input)
{
Dictionary<string, int> wordCounts = new(StringComparer.OrdinalIgnoreCase);
Dictionary<string, int>.AlternateLookup<ReadOnlySpan<char>> spanLookup =
wordCounts.GetAlternateLookup<string, int, ReadOnlySpan<char>>();
wordCounts.GetAlternateLookup<ReadOnlySpan<char>>();

foreach (Range wordRange in Regex.EnumerateSplits(input, @"\b\w+\b"))
{
Expand Down
25 changes: 25 additions & 0 deletions docs/core/whats-new/snippets/dotnet-9/csharp/Compression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.IO;
using System.IO.Compression;

namespace Project;
internal class Compression
{
// <CompressStream>
private MemoryStream CompressStream(Stream uncompressedStream)
{
MemoryStream compressorOutput = new();
using ZLibStream compressionStream = new(
compressorOutput,
new ZLibCompressionOptions()
{
CompressionLevel = 6,
CompressionStrategy = ZLibCompressionStrategy.HuffmanOnly
}
);
uncompressedStream.CopyTo(compressionStream);
compressionStream.Flush();

return compressorOutput;
}
// </CompressStream>
}
62 changes: 58 additions & 4 deletions docs/core/whats-new/snippets/dotnet-9/csharp/Diagnostics.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System.Diagnostics;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Diagnostics.Tracing;

internal class Diagnostics
{
Expand All @@ -14,13 +17,64 @@ public static void RunIt()
// </AddLink>

// <Gauge>
Meter meter = new("MeasurementLibrary.Sound");
Gauge<int> gauge = meter.CreateGauge<int>(
Meter soundMeter = new("MeasurementLibrary.Sound");
Gauge<int> gauge = soundMeter.CreateGauge<int>(
name: "NoiseLevel",
unit: "dB", // Decibels.
description: "Background Noise Level"
);
gauge.Record(10, new TagList() { { "Room1", "dB" } } );
gauge.Record(10, new TagList() { { "Room1", "dB" } });
// </Gauge>

// <Wildcard>
// The complete meter name is "MyCompany.MyMeter".
var meter = new Meter("MyCompany.MyMeter");
// Create a counter and allow publishing values.
meter.CreateObservableCounter("MyCounter", () => 1);

// Create the listener to use the wildcard character
// to listen to all meters using prefix names.
MyEventListener listener = new MyEventListener();
// </Wildcard>
}
}

// <EventListener>
internal class MyEventListener : EventListener
{
protected override void OnEventSourceCreated(EventSource eventSource)
{
Console.WriteLine(eventSource.Name);
if (eventSource.Name == "System.Diagnostics.Metrics")
{
// Listen to all meters with names starting with "MyCompany".
// If using "*", allow listening to all meters.
EnableEvents(
eventSource,
EventLevel.Informational,
(EventKeywords)0x3,
new Dictionary<string, string?>() { { "Metrics", "MyCompany*" } }
);
}
}

protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
// Ignore other events.
if (eventData.EventSource.Name != "System.Diagnostics.Metrics" ||
eventData.EventName == "CollectionStart" ||
eventData.EventName == "CollectionStop" ||
eventData.EventName == "InstrumentPublished"
)
return;

Console.WriteLine(eventData.EventName);

if (eventData.Payload is not null)
{
for (int i = 0; i < eventData.Payload.Count; i++)
Console.WriteLine($"\t{eventData.PayloadNames![i]}: {eventData.Payload[i]}");
}
}
}
// </EventListener>
Loading

0 comments on commit 17d020b

Please sign in to comment.