|
2 | 2 | title: What's new in .NET libraries for .NET 10 |
3 | 3 | description: Learn about the updates to the .NET libraries for .NET 10. |
4 | 4 | titleSuffix: "" |
5 | | -ms.date: 07/16/2025 |
| 5 | +ms.date: 08/12/2025 |
6 | 6 | ms.topic: whats-new |
7 | 7 | ai-usage: ai-assisted |
8 | 8 | --- |
9 | 9 |
|
10 | 10 | # What's new in .NET libraries for .NET 10 |
11 | 11 |
|
12 | | -This article describes new features in the .NET libraries for .NET 10. It's been updated for Preview 6. |
| 12 | +This article describes new features in the .NET libraries for .NET 10. It's been updated for Preview 7. |
13 | 13 |
|
14 | 14 | ## Cryptography |
15 | 15 |
|
@@ -113,6 +113,73 @@ private static bool ValidateMLDsaSignature(ReadOnlySpan<byte> data, ReadOnlySpan |
113 | 113 |
|
114 | 114 | The PQC algorithms are available on systems where the system cryptographic libraries are OpenSSL 3.5 (or newer) or Windows CNG with PQC support. Also, the new classes are all marked as [`[Experimental]`](../../../fundamentals/syslib-diagnostics/experimental-overview.md) under diagnostic `SYSLIB5006` until development is complete. |
115 | 115 |
|
| 116 | +#### ML-DSA |
| 117 | + |
| 118 | +The <xref:System.Security.Cryptography.MLDsa> class includes ease-of-use features that simplify common code patterns: |
| 119 | + |
| 120 | +```diff |
| 121 | +private static byte[] SignData(string privateKeyPath, ReadOnlySpan<byte> data) |
| 122 | +{ |
| 123 | + using (MLDsa signingKey = MLDsa.ImportFromPem(File.ReadAllBytes(privateKeyPath))) |
| 124 | + { |
| 125 | +- byte[] signature = new byte[signingKey.Algorithm.SignatureSizeInBytes]; |
| 126 | +- signingKey.SignData(data, signature); |
| 127 | ++ return signingKey.SignData(data); |
| 128 | +- return signature; |
| 129 | + } |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +Additionally, this release added support for HashML-DSA, which is called "PreHash" to help distinguish it from "pure" ML-DSA. As the underlying specification interacts with the Object Identifier (OID) value, the SignPreHash and VerifyPreHash methods on this `[Experimental]` type take the dotted-decimal OID as a string. This might evolve as more scenarios using HashML-DSA become well-defined. |
| 134 | + |
| 135 | +```csharp |
| 136 | +private static byte[] SignPreHashSha3_256(MLDsa signingKey, ReadOnlySpan<byte> data) |
| 137 | +{ |
| 138 | + const string Sha3_256Oid = "2.16.840.1.101.3.4.2.8"; |
| 139 | + return signingKey.SignPreHash(SHA3_256.HashData(data), Sha3_256Oid); |
| 140 | +} |
| 141 | +``` |
| 142 | + |
| 143 | +#### Composite ML-DSA |
| 144 | + |
| 145 | +.NET 10 introduces new types to support [ietf-lamps-pq-composite-sigs](https://datatracker.ietf.org/doc/draft-ietf-lamps-pq-composite-sigs/) (currently at draft 7), including `CompositeMLDsa` and `CompositeMLDsaAlgorithm` types with implementation of the primitive methods for RSA variants. |
| 146 | + |
| 147 | +```csharp |
| 148 | +var algorithm = CompositeMLDsaAlgorithm.MLDsa65WithRSA4096Pss; |
| 149 | +using var privateKey = CompositeMLDsa.GenerateKey(algorithm); |
| 150 | + |
| 151 | +byte[] data = [42]; |
| 152 | +byte[] signature = privateKey.SignData(data); |
| 153 | + |
| 154 | +using var publicKey = CompositeMLDsa.ImportCompositeMLDsaPublicKey(algorithm, privateKey.ExportCompositeMLDsaPublicKey()); |
| 155 | +Console.WriteLine(publicKey.VerifyData(data, signature)); // True |
| 156 | +
|
| 157 | +signature[0] ^= 1; // Tamper with signature |
| 158 | +Console.WriteLine(publicKey.VerifyData(data, signature)); // False |
| 159 | +``` |
| 160 | + |
| 161 | +### AES KeyWrap with Padding (IETF RFC 5649) |
| 162 | + |
| 163 | +AES-KWP is an algorithm that is occasionally used in constructions like Cryptographic Message Syntax (CMS) EnvelopedData, where content is encrypted once, but the decryption key needs to be distributed to multiple parties, each one in a distinct secret form. |
| 164 | + |
| 165 | +.NET now supports the AES-KWP algorithm via instance methods on the <xref:System.Security.Cryptography.Aes> class: |
| 166 | + |
| 167 | +```csharp |
| 168 | +private static byte[] DecryptContent(ReadOnlySpan<byte> kek, ReadOnlySpan<byte> encryptedKey, ReadOnlySpan<byte> ciphertext) |
| 169 | +{ |
| 170 | + using (Aes aes = Aes.Create()) |
| 171 | + { |
| 172 | + aes.SetKey(kek); |
| 173 | + |
| 174 | + Span<byte> dek = stackalloc byte[256 / 8]; |
| 175 | + int length = aes.DecryptKeyWrapPadded(encryptedKey, dek); |
| 176 | + |
| 177 | + aes.SetKey(dek.Slice(0, length)); |
| 178 | + return aes.DecryptCbc(ciphertext); |
| 179 | + } |
| 180 | +} |
| 181 | +``` |
| 182 | + |
116 | 183 | ## Globalization and date/time |
117 | 184 |
|
118 | 185 | - [New method overloads in ISOWeek for DateOnly type](#new-method-overloads-in-isoweek-for-dateonly-type) |
@@ -183,6 +250,7 @@ This new API is already used in <xref:System.Json.JsonObject> and improves the p |
183 | 250 | - [Allow specifying ReferenceHandler in `JsonSourceGenerationOptions`](#allow-specifying-referencehandler-in-jsonsourcegenerationoptions) |
184 | 251 | - [Option to disallow duplicate JSON properties](#option-to-disallow-duplicate-json-properties) |
185 | 252 | - [Strict JSON serialization options](#strict-json-serialization-options) |
| 253 | +- [PipeReader support for JSON serializer](#pipereader-support-for-json-serializer) |
186 | 254 |
|
187 | 255 | ### Allow specifying ReferenceHandler in `JsonSourceGenerationOptions` |
188 | 256 |
|
@@ -224,6 +292,37 @@ These options are read-compatible with <xref:System.Text.Json.JsonSerializerOpti |
224 | 292 |
|
225 | 293 | For more information about JSON serialization, see [System.Text.Json overview](../../../standard/serialization/system-text-json/overview.md). |
226 | 294 |
|
| 295 | +### PipeReader support for JSON serializer |
| 296 | + |
| 297 | +<xref:System.Text.Json.JsonSerializer.Deserialize%2A?displayProperty=nameWithType> now supports <xref:System.IO.Pipelines.PipeReader>, complementing the existing <xref:System.IO.Pipelines.PipeWriter> support. Previously, deserializing from a `PipeReader` required converting it to a <xref:System.IO.Stream>, but the new overloads eliminate that step by integrating `PipeReader` directly into the serializer. As a bonus, not having to convert from what you're already holding can yield some efficiency benefits. |
| 298 | + |
| 299 | +This shows the basic usage: |
| 300 | + |
| 301 | +:::code language="csharp" source="snippets/csharp/PipeReaderBasic.cs"::: |
| 302 | + |
| 303 | +Here is an example of a producer that produces tokens in chunks and a consumer that receives and displays them: |
| 304 | + |
| 305 | +:::code language="csharp" source="snippets/csharp/PipeReaderChunks.cs"::: |
| 306 | + |
| 307 | +All of this is serialized as JSON in the <xref:System.IO.Pipelines.Pipe> (formatted here for readability): |
| 308 | + |
| 309 | +```json |
| 310 | +[ |
| 311 | + { |
| 312 | + "Message": "The quick brown fox", |
| 313 | + "Timestamp": "2025-08-01T18:37:27.2930151-07:00" |
| 314 | + }, |
| 315 | + { |
| 316 | + "Message": " jumps over", |
| 317 | + "Timestamp": "2025-08-01T18:37:27.8594502-07:00" |
| 318 | + }, |
| 319 | + { |
| 320 | + "Message": " the lazy dog.", |
| 321 | + "Timestamp": "2025-08-01T18:37:28.3753669-07:00" |
| 322 | + } |
| 323 | +] |
| 324 | +``` |
| 325 | + |
227 | 326 | ## System.Numerics |
228 | 327 |
|
229 | 328 | - [More left-handed matrix transformation methods](#more-left-handed-matrix-transformation-methods) |
@@ -328,3 +427,85 @@ A community contribution improved the performance of <xref:System.IO.Compression |
328 | 427 |
|
329 | 428 | - Eliminates repeated allocation of ~64-80 bytes of memory per concatenated stream, with additional unmanaged memory savings. |
330 | 429 | - Reduces execution time by approximately 400 ns per concatenated stream. |
| 430 | + |
| 431 | +## Windows process management |
| 432 | + |
| 433 | +### Launch Windows processes in new process group |
| 434 | + |
| 435 | +For Windows, you can now use <xref:System.Diagnostics.ProcessStartInfo.CreateNewProcessGroup?displayProperty=nameWithType> to launch a process in a separate process group. This allows you to send isolated signals to child processes that could otherwise take down the parent without proper handling. Sending signals is convenient to avoid forceful termination. |
| 436 | + |
| 437 | +:::code language="csharp" source="snippets/csharp/ProcessGroup.cs"::: |
| 438 | + |
| 439 | +## WebSocket enhancements |
| 440 | + |
| 441 | +### WebSocketStream |
| 442 | + |
| 443 | +.NET 10 introduces `WebSocketStream` <!--<xref:System.Net.WebSockets.WebSocketStream>-->, a new API designed to simplify some of the most common—and previously cumbersome—<xref:System.Net.WebSockets.WebSocket> scenarios in .NET. |
| 444 | + |
| 445 | +Traditional `WebSocket` APIs are low-level and require significant boilerplate: handling buffering and framing, reconstructing messages, managing encoding/decoding, and writing custom wrappers to integrate with streams, channels, or other transport abstractions. These complexities make it difficult to use WebSockets as a transport, especially for apps with streaming or text-based protocols, or event-driven handlers. |
| 446 | + |
| 447 | +`WebSocketStream` addresses these pain points by providing a <xref:System.IO.Stream>-based abstraction over a WebSocket. This enables seamless integration with existing APIs for reading, writing, and parsing data, whether binary or text, and reduces the need for manual plumbing. |
| 448 | + |
| 449 | +`WebSocketStream` enables high-level, familiar APIs for common WebSocket consumption and production patterns. These APIs reduce friction and make advanced scenarios easier to implement. |
| 450 | + |
| 451 | +#### Common usage patterns |
| 452 | + |
| 453 | +Here are a few examples of how `WebSocketStream` simplifies typical `WebSocket` workflows: |
| 454 | + |
| 455 | +##### Streaming text protocol (for example, STOMP) |
| 456 | + |
| 457 | +:::code language="csharp" source="snippets/csharp/WebSocketStreamText.cs"::: |
| 458 | + |
| 459 | +##### Streaming binary protocol (for example, AMQP) |
| 460 | + |
| 461 | +:::code language="csharp" source="snippets/csharp/WebSocketStreamBinary.cs"::: |
| 462 | + |
| 463 | +##### Read a single message as a stream (for example, JSON deserialization) |
| 464 | + |
| 465 | +:::code language="csharp" source="snippets/csharp/WebSocketStreamRead.cs"::: |
| 466 | + |
| 467 | +##### Write a single message as a stream (for example, binary serialization) |
| 468 | + |
| 469 | +:::code language="csharp" source="snippets/csharp/WebSocketStreamWrite.cs"::: |
| 470 | + |
| 471 | +## TLS enhancements |
| 472 | + |
| 473 | +### TLS 1.3 for macOS (client) |
| 474 | + |
| 475 | +.NET 10 adds client-side TLS 1.3 support on macOS by integrating Apple's Network.framework into <xref:System.Net.Security.SslStream> and <xref:System.Net.Http.HttpClient>. Historically, macOS used Secure Transport which doesn't support TLS 1.3; opting into Network.framework enables TLS 1.3. |
| 476 | + |
| 477 | +#### Scope and behavior |
| 478 | + |
| 479 | +- macOS only, client-side in this release. |
| 480 | +- Opt-in. Existing apps continue to use the current stack unless enabled. |
| 481 | +- When enabled, older TLS versions (TLS 1.0 and 1.1) might no longer be available via Network.framework. |
| 482 | + |
| 483 | +#### How to enable |
| 484 | + |
| 485 | +Use an AppContext switch in code: |
| 486 | + |
| 487 | +```csharp |
| 488 | +// Opt in to Network.framework-backed TLS on Apple platforms |
| 489 | +AppContext.SetSwitch("System.Net.Security.UseNetworkFramework", true); |
| 490 | + |
| 491 | +using var client = new HttpClient(); |
| 492 | +var html = await client.GetStringAsync("https://example.com"); |
| 493 | +``` |
| 494 | + |
| 495 | +Or use an environment variable: |
| 496 | + |
| 497 | +```bash |
| 498 | +# Opt-in via environment variable (set for the process or machine as appropriate) |
| 499 | +DOTNET_SYSTEM_NET_SECURITY_USENETWORKFRAMEWORK=1 |
| 500 | +# or |
| 501 | +DOTNET_SYSTEM_NET_SECURITY_USENETWORKFRAMEWORK=true |
| 502 | +``` |
| 503 | + |
| 504 | +#### Notes |
| 505 | + |
| 506 | +- TLS 1.3 applies to <xref:System.Net.Security.SslStream> and APIs built on it (for example, <xref:System.Net.Http.HttpClient>/<xref:System.Net.Http.HttpMessageHandler>). |
| 507 | +- Cipher suites are controlled by macOS via Network.framework. |
| 508 | +- Underlying stream behavior might differ when Network.framework is enabled (for example, buffering, read/write completion, cancellation semantics). |
| 509 | +- Semantics might differ for zero-byte reads. Avoid relying on zero-length reads for detecting data availability. |
| 510 | +- Certain internationalized domain names (IDN) hostnames might be rejected by Network.framework. Prefer ASCII/Punycode (A-label) hostnames or validate names against macOS/Network.framework constraints. |
| 511 | +- If your app relies on specific <xref:System.Net.Security.SslStream> edge-case behavior, validate it under Network.framework. |
0 commit comments