What to Expect in .NET 8 (A Summary)


.NET 8 is a long-term support (LTS) release. .NET 8 is the successor to .NET 7. It will be supported for three years, in this article we will look into the enhancements and new features introduced with this release including C# 12, EF Core 8 and ASP.NET Core 8.0. Today it's still in preview (version 6), but you can download the SDK and play around from here.

Improvements to System.Text.Json 

You can customize handling of members that aren't in the JSON payload: By default, if the JSON payload you're deserializing contains properties that don't exist in the deserialized plain old CLR object (POCO) type, they're simply ignored. Starting in .NET 8, you can specify that all members must be present in the payload. If they're not, a JsonException exception is thrown.
 
 
Interface hierarchies: .NET 8 adds 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.

 

Core .NET libraries

The new TimeProvider class and ITimer interface add time abstraction functionality, which allows you to mock time in test scenarios. The time abstraction supports the following essential time operations:
  • Retrieve local and UTC time
  • Obtain a timestamp for measuring performance
  • Create a timer
The following code snippet shows some usage examples.

Also The System.Random and System.Security.Cryptography.RandomNumberGenerator types introduce two new methods for working with randomness.

GetItems<T>()

The new System.Random.GetItems and System.Security.Cryptography.RandomNumberGenerator.GetItems 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 Random.Shared property) to randomly insert 31 items into an array.


Shuffle<T>()

The new Random.Shuffle and RandomNumberGenerator.Shuffle<T>(Span<T>) methods let you randomize the order of a span. These methods are useful for reducing training bias in machine learning.

Data validation

The System.ComponentModel.DataAnnotations namespace includes new data validation attributes intended for validation scenarios in cloud-native services. While the pre-existing DataAnnotations validators are geared towards typical UI data-entry validation, such as fields on a form, the new attributes are designed to validate non-user-entry data, such as configuration options. In addition to the new attributes, new properties were added to the RangeAttribute and RequiredAttribute types.

New APIDescription
RangeAttribute.MinimumIsExclusive
RangeAttribute.MaximumIsExclusive
Specifies whether bounds are included in the allowable range.
System.ComponentModel.DataAnnotations.LengthAttributeSpecifies both lower and upper bounds for strings or collections. For example, [Length(10, 20)] requires at least 10 elements and at most 20 elements in a collection.
System.ComponentModel.DataAnnotations.Base64StringAttributeValidates that a string is a valid Base64 representation.
System.ComponentModel.DataAnnotations.AllowedValuesAttribute
System.ComponentModel.DataAnnotations.DeniedValuesAttribute
Specify allow lists and deny lists, respectively. For example, [AllowedValues("apple", "banana", "mango")].

Cryptography

.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_256SHA3_384, and SHA3_512 for hashing; HMACSHA3_256HMACSHA3_384, and HMACSHA3_512 for HMAC. The following example shows how to use the APIs, including the SHA3_256.IsSupported property to determine if the platform supports SHA-3.

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. For now, the _RefreshMemoryLimit API is private, so you'll need to call it through private reflection.

The following code snippet sets the heap hard limit to 100 mebibytes (MiB):


Native AOT support

The option to publish as native AOT 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. .NET 8 brings the following improvements to native AOT publishing:
  • Adds support for the x64 and Arm64 architectures on macOS.
  • Reduces the sizes of native AOT apps on Linux by up to 50%.
The default console app template now includes support for AOT out-of-the-box. To create a project that's configured for AOT compilation, just run dotnet new console --aot. The project configuration added by --aot generates a native self-contained executable with native AOT when you publish the project, for example, with dotnet publish or Visual Studio.

Performance improvements

.NET 8 includes improvements to code generation and just-in time (JIT) compilation:
  • Arm64 performance improvements
  • SIMD improvements
  • Support for AVX-512 ISA extensions (see Vector512 and AVX-512)
  • Cloud-native improvements
  • JIT throughput improvements
  • Loop and general optimizations

.NET SDK changes

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.

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.

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.

EF Core 8

EF7 already introduced Raw SQL queries for scalar types, however, in EF8, raw SQL queries can now return any mappable CLR type not included in the Entity Framework model. Queries executed this way support Entity Framework features such as parametrized constructors and mapping attributes. Notably, relationships between the un-mapped type and other types in the model are not supported, since the un-mapped model cannot have foreign keys defined.

DateOnly/TimeOnly supported on SQL Server

The DateOnly and TimeOnly types were introduced in .NET 6 and have been supported for several database providers (e.g. SQLite, MySQL, and PostgreSQL) since their introduction. For SQL Server, the recent release of a Microsoft.Data.SqlClient package targeting .NET 6 has allowed ErikEJ to add support for these types at the ADO.NET level. This in turn paved the way for support in EF8 for DateOnly and TimeOnly as properties in entity types.

Previously, when scaffolding a SQL Server database with date or time columns, EF would generate entity properties with types DateTime and TimeSpan. Starting with EF Core 8.0, date and time are scaffolded as DateOnly and TimeOnly. [Breaking Changes]

Lazy-loading for no-tracking queries

EF8 adds support for lazy-loading of navigations on entities that are not being tracked by the DbContext. This means a no-tracking query can be followed by lazy-loading of navigations on the entities returned by the no-tracking query. For example, consider a no-tracking query for blogs:

If Blog.Posts is configured for lazy-loading, for example, using lazy-loading proxies, then accessing Posts will cause it to load from the database. EF8 also reports whether or not a given navigation is loaded for entities not tracked by the context. For example,

C# 12

Improved Switch Expressions

Switch expressions were introduced in C# 8, allowing developers to express complex conditional logic concisely and readably. In C# 12 a new pattern-matching syntax is introduced for switch expressions, which makes writing expressive and concise code even more accessible. 
For example, the below switch expression determines whether an integer is positive, negative, or zero. 
With C# 12, we can simplify this code even further as shown below:

Async Streams

You can iterate through asynchronous data sources with the new async streams feature of C# 12.


Default lambda parameters

You can now define default values for parameters on lambda expressions. The syntax and rules are the same as adding default values for arguments to any method or local function.

You can learn more about default parameters on lambda expressions in the article on lambda expressions.

ASP.NET Core 8.0

SignalR: New approach to set the server timeout and Keep-Alive interval

ServerTimeout (default: 30 seconds) and KeepAliveInterval (default: 15 seconds) can be set directly on HubConnectionBuilder.
Prior approach for JavaScript clients:

New approach for JavaScript clients:

HTTP/3 enabled by default in Kestrel

HTTP/3 is a new internet technology that was standardized in June 2022. HTTP/3 offers several advantages over older HTTP protocols, including:
  • Faster connection setup.
  • No head-of-line blocking.
  • Better transitions between networks.
.NET 7 added support for HTTP/3 to ASP.NET Core and Kestrel. ASP.NET Core apps could choose to turn it on. In .NET 8, HTTP/3 is enabled by default for Kestrel, alongside HTTP/1.1 and HTTP/2.

Support for generic attributes

Attributes that previously required a Type parameter are now available in cleaner generic variants. This is made possible by support for generic attributes in C# 11. For example, the syntax for annotating the response type of an action can be modified as follows:

Manage Request Timeouts

Microsoft presents a new middleware for handling request timeouts. Now, you can easily set timeouts for specific endpoints, controllers, or on-the-fly per request.
First, add the request timeout services:

builder.Services.AddRequestTimeouts();

Next, apply request timeouts using middleware with UseRequestTimeouts():

app.UseRequestTimeouts();

For specific endpoints, use WithRequestTimeout(timeout) or add [RequestTimeout(timeout)] to the controller or action.

Keep in mind, timeouts are cooperative. When they expire, HttpContext.RequestAborted triggers, but requests won’t be forcibly stopped. Your app should keep an eye on the token and decide when to wrap up request processing


Conclusion

In conclusion, .NET 8 and ASP.NET 8 have introduced an array of exciting new features that enhance the development experience and pave the way for more efficient and powerful applications. With these enhancements, .NET 8 and ASP.NET 8 solidify their positions as top choices for developers, enabling them to build cutting-edge solutions across a variety of platforms and industries. As the .NET ecosystem continues to evolve, it is evident that these new features mark yet another step forward in delivering a more robust and enjoyable development experience.

Read more