21
Nov.NET 8 Features - What's new in .NET 8?
.Net 8 Features: An Overview
.NET 8 is a free, cross-platform, and open-source programming framework that enables the development of various web, mobile, and cloud computing applications. This powerful open-source development platform has been driving the software industry for years. With every release of a new version, the technocrats become empowered to build more powerful, efficient, and secure applications.
Since its inception, the .NET framework has announced seven releases, each with a new set of enhancements. Recently, the successor of .NET 7, .NET 8, was released. .NET 8 is not only a framework version but is much more than that. It redefines the way software applications are built and deployed, enabling developers to meet the evolving demands of modern computing. It offers enhanced performance, improved diagnostic and observability, expanded cross-platform support, advanced tooling and integration, long-term support (LTS), and much more.
In this .NET tutorial, we'll discuss Microsoft's latest improvements and additions to the .NET 8 version.
For a detailed understanding, do consider:
- .NET Developer Training With Certification
- ASP.NET Core Certification Training
- .NET Solution Architect Certification Training
Upgrades and Enhancements in .NET 8
Let's explore everything one by one:
- Software Development Kit (SDK) Changes
- Terminal Build Output
The dotnet build command builds a project and its dependencies into a set of binaries. In .NET 8, this command offers a new option to produce a more modernized build output. This terminal logger output enhances the grouping of errors based on their respective projects, improves the distinction between different target frameworks in multi-targeted projects, and offers real-time updates on the build process.
- Simplified Output Paths
Now, you can streamline the output path and folder structure for build outputs. All the build outputs are consolidated into a unified location. This change facilitates better predictability and compatibility with various development tools and utilities.
Read More - Advanced .Net Interview Questions
- Dotnet Workload Clean Command
This is a new command to clean up any leftover workload packs that may accumulate over multiple .NET Software Development Kit (SDK) or Visual Studio updates.
- Dotnet Publish and Dotnet Pack Assets
In .NET 8, the default behavior of the dotnet publish and dotnet pack commands has been updated to generate Release assets instead of Debug assets. These commands could be used to build and package your code for different purposes.
The dotnet build command prepares your code for execution and places the output in the Debug folder. Whereas, the dotnet publish command prepares your code for production use and saves the output in the Release folder.
- Template Engine
Now, the template engine has been enhanced to provide a more secure experience as it has included security features from NuGet. These improvements are as follows:
- Preventing downloading packages from insecure http:// feeds. Therefore, if a source URL does not use https, attempting to install the template package will fail.
- For commands such as dotnet new, dotNET new install, and dotnet new update, the template engine now checks for known vulnerabilities in the template package.
- The dotnet new command now provides information about the owner of the template package.
- The dotnet search and dotnet uninstall commands indicate whether a template is installed from a package that is considered “trusted.” Trusted packages use a reserved prefix, indicating their reliability.
- Core .NET Libraries
- Time Abstraction
The new TimeProvider class and ITimer interface in .NET 8 enable mock time in test scenarios. It even provides functionalities to retrieve local and UTC, obtain timestamps for performance measurement, and create timers.
- UTF8 Improvements
The introduction of the IUtf8SpanFormattable interface in .NET 8 enables writing string-like representations of your data type to UTF8 destinations. It also supports formatting to UTF8 from various primitive data types and provides TryWrite methods for UTF8-based formatting.
Example
static bool FormatHexVersion(
short major,
short minor,
short build,
short revision,
Span utf8Bytes,
out int bytesWritten) =>
Utf8.TryWrite(
utf8Bytes,
CultureInfo.InvariantCulture,
$"{major:X4}.{minor:X4}.{build:X4}.{revision:X4}",
out bytesWritten);
The implementation recognizes IUtf8SpanFormattable on the format values and uses their implementations to write their UTF8 representations directly to the destination span.
- Methods for Working with Randomness
The System.Random and System.Security.Cryptography.RandomNumberGenerator data types in .NET introduce new methods for working with randomness. These include GetItems() for randomly choosing items from an input set and Shuffle() for reducing training bias in machine learning.
The following example shows how to use System.Random.GetItems
Example of System.Random.GetItems<T>()
private static ReadOnlySpan<button> s_allButtons = new[]
{
Button.Red,
Button.Green,
Button.Blue,
Button.Yellow,
};
// ...
Button[] thisRound = Random.Shared.GetItems(s_allButtons, 31);
// Rest of game goes here ...
Example of Shuffle<T>()
YourType[] trainingData = LoadTrainingData();
Random.Shared.Shuffle(trainingData);
IDataView sourceData = mlContext.Data.LoadFromEnumerable(trainingData);
DataOperationsCatalog.TrainTestData split = mlContext.Data.TrainTestSplit(sourceData);
model = chain.Fit(split.TrainSet);
IDataView predictions = model.Transform(split.TestSet);
// ...
- Performance-Focused Data Types
The new System.Collections.Frozen namespace in .NET 8 introduces FrozenDictionary
private static readonly FrozenDictionary<string, bool> s_configurationData =
LoadConfigurationData().ToFrozenDictionary(optimizeForReads: true);
// ...
if (s_configurationData.TryGetValue(key, out bool setting) && setting)
{
Process();
}
- System.Numerics and System.Runtime.Intrinsics
Vector256, Matrix3x2, and Matrix4x4 have improved the hardware acceleration on .NET 8. The hardware intrinsics in .NET 8 are annotated with the ConstExpected attribute, ensuring you get information on when the underlying hardware expects a constant or a non-constant. Also, the added Lerp(TSelf, TSelf, TSelf) API provides linear interpolation between the two values to be performed efficiently and accurately.
- Data Validation
The System.ComponentModel.DataAnnotations namespace in .NET 8 includes new attributes for data validation in cloud-native services. These are specifically designed to validate non-user-entry data, such as configuration options.
- Extension of .NET Libraries
- ValidateOptionsResultBuilder Type
It simplifies the creation of ValidateOptionsResult objects, allowing for the accumulation of multiple errors during validation. This is particularly useful when implementing the IValidateOptions.Validate method because it enables better handling of validation errors.
Example of ValidateOptionsResultBuilder
ValidateOptionsResultBuilder builder = new();
builder.AddError("Error: invalid operation code");
builder.AddResult(ValidateOptionsResult.Fail("Invalid request parameters"));
builder.AddError("Malformed link", "Url");
// Build ValidateOptionsResult object has accumulating multiple errors.
ValidateOptionsResult result = builder.Build();
// Reset the builder to allow using it in new validation operation.
builder.Clear();
- Garbage Collection Memory Limit Adjustment
Now one can dynamically adjust the memory limit for garbage collection. Also, the _RefreshMemoryLimit API allows updating the garbage collector with the new memory limit, ensuring efficient resource utilization.
- Source Generator for Configuration Binding
ASP.NET Core uses configuration providers to read key-value pair data from various sources for app configuration. With the source generator in .NET 8, you can opt-in to generate binding implementations for configuration mapping. This eliminates the reliance on reflection – which causes issues with trimming and Native AOT – and improves performance and compatibility.
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
IConfigurationSection section = builder.Configuration.GetSection("MyOptions");
// !! Configure call - to be replaced with source-gen'd implementation
builder.Services.Configure(section);
// !! Get call - to be replaced with source-gen'd implementation
MyOptions options0 = section.Get();
// !! Bind call - to be replaced with source-gen'd implementation
MyOptions options1 = new MyOptions();
section.Bind(options1);
WebApplication app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
public class MyOptions
{
public int A { get; set; }
public string S { get; set; }
public byte[] Data { get; set; }
public Dictionary Values { get; set; }
public List Values2 { get; set; }
}
public class MyClass
{
public int SomethingElse { get; set; }
}
- Reflection Improvements
You might have observed that in the previous versions of .NET, an IntPtr was returned instead of a System.Type object while working with function pointers and using reflection operations like typeof or FieldInfo.FieldType. This limited the ability to access the metadata of function pointers, such as calling conventions, return types, and parameters.
However, in .NET 8, improvements have been made to reflection to support function pointers. Now, when using typeof or working with FieldInfo.FieldType on a function pointer, a System.Type object is returned. This enables you to access and utilize the metadata associated with function pointers, allowing for more comprehensive reflection operations on these data types.
Example of some of the new APIs for Reflection Improvements
// Sample class that contains a function pointer field.
public unsafe class UClass
{
public delegate* unmanaged[Cdecl, SuppressGCTransition] _fp;
}
// ...
FieldInfo fieldInfo = typeof(UClass).GetField(nameof(UClass._fp));
// Obtain the function pointer type from a field.
Type fpType = fieldInfo.FieldType;
// New methods to determine if a type is a function pointer.
Console.WriteLine(
$"IsFunctionPointer: {fpType.IsFunctionPointer}");
Console.WriteLine(
$"IsUnmanagedFunctionPointer: {fpType.IsUnmanagedFunctionPointer}");
// New methods to obtain the return and parameter types.
Console.WriteLine($"Return type: {fpType.GetFunctionPointerReturnType()}");
foreach (Type parameterType in fpType.GetFunctionPointerParameterTypes())
{
Console.WriteLine($"Parameter type: {parameterType}");
}
// Access to custom modifiers and calling conventions requires a "modified type".
Type modifiedType = fieldInfo.GetModifiedFieldType();
// A modified type forwards most members to its underlying type.
Type normalType = modifiedType.UnderlyingSystemType;
// New method to obtain the calling conventions.
foreach (Type callConv in modifiedType.GetFunctionPointerCallingConventions())
{
Console.WriteLine($"Calling convention: {callConv}");
}
// New method to obtain the custom modifiers.
var modifiers =
modifiedType.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers();
foreach (Type modreq in modifiers)
{
Console.WriteLine($"Required modifier for first parameter: {modreq}");
}
Output
IsFunctionPointer: True
IsUnmanagedFunctionPointer: True
Return type: System.Void
Parameter type: System.Int32&
Calling convention: System.Runtime.CompilerServices.CallConvSuppressGCTransition
Calling convention: System.Runtime.CompilerServices.CallConvCdecl
Required modifier for first parameter: System.Runtime.InteropServices.InAttribute
- Native Ahead-of-Time (AOT) Compilation
Unlike traditional just-in-time (JIT) compilation, where code is compiled to machine code at runtime, Native AOT compiles managed code directly into native machine code during the build process. Native AOT enables the creation of a self-contained version of the app that does not require a separate runtime, bundling everything into a single file.
To understand the significance of Native AOT, let’s get into its major aspects:
- Improved Startup Time: In traditional JIT compilation, the first execution of a method incurs a compilation delay, impacting application startup times. However, with Native AOT, the compilation process occurs during the build phase. Consequently, .NET 8 applications experience minimal warm-up times and respond instantaneously to user interactions.
- Reduced Memory Footprint: By compiling directly to native code, Native AOT reduces the memory footprint of .NET applications.
- Performance Improvements
- Arm64 performance enhancements
- Single Instruction, Multiple Data (SIMD) improvements
- Support for AVX-512 (Advanced Vector Extensions) ISA extensions
- Cloud-native improvements
- Profile-Guided Optimization (PGO) improvements
- Just-in-Time (JIT) throughput improvements
- Loop and general optimizations
- Optimized access for fields marked with ThreadStaticAttribute
- Consecutive register allocation
- JIT/NativeAOT memory operations
- Security Enhancements
- Secure Software Supply Chain Capabilities
.NET 8 addresses security vulnerabilities by enabling cryptographic signing of assemblies, allowing developers to verify the authenticity and integrity of dependencies before they are integrated into the application.
Moreover, .NET 8 emphasizes secure source control practices, facilitating the use of signed Git commits and ensuring that the source code remains secure throughout its development lifecycle. By enforcing secure source control practices, .NET 8 minimizes the risk of unauthorized changes and malicious code injections, reinforcing the integrity of the application’s source code.
- Improvements to Auth and Identity in ASP.NET Core
New APIs will make authentication, authorization, and identity management (collectively referred to as “auth”) easier to customize the user login and identity management experience. New endpoints will enable token-based authentication and authorization in Single Page Applications (SPA) with no external dependencies.
- Code Generation Enhancements
The .NET 8 release introduced some significant code generation enhancements that can contribute to faster and more efficient execution of .NET applications.
- Advanced Memory Management
By reducing memory fragmentation and improving memory locality, applications can better leverage system resources, resulting in smoother performance and reduced memory-related bottlenecks.
- Enhanced Optimization Techniques
In .NET 8 the compiler intelligently analyzes the code, identifies opportunities for optimizations, and generates highly efficient machine code. These optimizations range from loop unrolling and constant folding to inlining and dead code elimination, resulting in faster and more streamlined execution paths.
- Hardware-Specific Instructions
By generating code that utilizes specialized instructions available on modern CPUs, such as SIMD (Single Instruction, Multiple Data) instructions, .NET 8 significantly boosts the performance of applications that perform vectorized computations and data parallelism.
- Serialization Improvements
In .NET 8, several improvements have been made to the serialization and deserialization functionality of System.Text.Json. These are as follows:
- Performance and reliability enhancements for the source generator in native AOT apps.
- Support for serializing types with required and init properties.
- Customization of handling members that are not present in the JSON payload.
- Explicit control over frozen JsonSerializerOptions instances.
- Replacement of deprecated AddContext() method with TypeInfoResolver and TypeInfoResolverChain properties.
- Support for compiler-generated or unspeakable types in weakly typed source generation scenarios, allowing System.Text.Json to dynamically determine the appropriate supertype for serialization at runtime.
Read More:
- .NET8 Developer Roadmap for 2024
- What is the difference between .NET 7 and 8?
- Why a Tech Stack .NET Developer Should Upskill?
- .NET Developer Should Learn Azure or AWS?
Summary
In this blog post, we have seen some of the important updates in .NET 8. These improvements will make the development smooth for the developers. Microsoft’s .NET 8 release is a major leap forward in building scalable, secure, robust, and performant applications. With the release of .NET 8, C# 12 was also made available. To get into more details, enroll in our .NET Training Program.
FAQs
- Performance Improvements:.NET 8 expands on the performance improvements offered in.NET 7, making programs faster, particularly in cases involving serialization, regular expressions, and web development.
- Native AOT (Ahead-of-Time) Improvements:.NET 8 builds on the foundation of AOT, which was introduced in.NET 7. AOT converts apps into native code, resulting in faster startup times and lower memory utilization.
- Container Optimization: Both.NET 7 and.NET 8 focus extensively on containerized apps, but.NET 8 further extends these optimizations to improve performance.
- Long-Term Support (LTS): .NET 6 is a stable release with long-term support, making it a go-to version for production applications that require extended maintenance.
- Cross-platform Development: Supports building applications for Linux, macOS, and Windows.
- C# 10: Introduced new language features such as global using directives, record struct, and more.
- Minimal APIs: Introduced minimal APIs for simpler and more efficient microservices development.
- Hot Reload: Improved developer productivity with the Hot Reload feature, enabling you to apply code changes without restarting the application
- Native AOT (Ahead-of-Time) Compilation: Further enhances AOT support for faster startup and reduced memory consumption.
- Performance Gains: Significant improvements in serialization, garbage collection, and regex matching, especially for cloud and web applications.
- Blazor Hybrid Apps: Extends the functionality of Blazor to build hybrid apps that can run on multiple platforms.
- Improved Containerization: Smaller and more efficient container images for cloud-native development.
- C# 12 Features: Introduces more advanced C# language features such as default type inference and better pattern matching.