In November 2023, Microsoft releases a new version of ASP.NET, a cross-platform open-source framework for building modern web-based applications with cloud support. So, what are the improvements compared to previous versions?
The release of ASP.NET Core 8.0 is part of a Microsoft policy that started with version .NET 5, which involves releasing a new version of the framework generally in November each year. The goal is to make the language more competitive by keeping it consistently updated with market demands.
This new version brings performance improvements, integration with emerging technologies, new APIs and libraries, as well as enhancements in container support and orchestration. Below you can find more details on some of these innovations.
New Blazor Web App model
In this new version, a new Blazor project template called Blazor Web App has been introduced, combining the features of both Blazor Server and Blazor WebAssembly. Other templates have been consolidated, simplifying the choice. Now, the Blazor Web App template can be used for various Blazor scenarios.
With this technology, it is now possible to stream content in real-time during the page rendering process. This advancement significantly enhances the user experience, allowing content to be displayed as it becomes available, even on pages involving time-consuming tasks such as extensive database queries.
Initially, the page is rendered with placeholders, and as asynchronous operations are completed, the updated content is streamed and integrated into the page in real-time. This approach not only speeds up page loading but also makes it more responsive to user interactions.
Now, you can create Razor components, like HTML in a text or flow format, without relying on HTTP requests or the ASP.NET Core hosting environment. This is useful when you need to generate HTML fragments, such as for creating e-mails or static website content.
Several enhancements for better performance
Code generation is crucial for the performance of applications in .NET, and the Just-in-Time (JIT) compiler is responsible for that. .NET 8 brings significant improvements to the JIT, including the use of dynamic Profile-Guided Optimisation (PGO), which represents a notable advancement in the quality and performance of generated code.
Dynamic PGO is a code optimisation strategy, which relies on the actual actions of a program as it runs, to improve its efficiency. It is called “dynamic” because it observes and collects data about the program’s behaviour in real-time and uses this information to create a more efficient version of the code.
Thanks to enhancements in the JIT, the process of zeroing variables has been optimised. When a significant amount of zeroing is required, the JIT now uses an optimised memory routine instead of generating a lot of code to achieve the same result. This improvement was made to optimise performance, making the process more efficient.
Another new feature in .NET 8 is vectorisation, a technique that takes advantage of the parallel processing power of hardware, such as modern Central Processing Units (CPUs), to execute operations efficiently. This is especially useful in mathematical operations and data manipulation, allowing you to process multiple pieces of information simultaneously, speeding up performance.
In .NET 8, the server Garbage Collector (GB) also has a new feature called Dynamic Adaptation To Application Sizes (DATAS), which allows automatic adjustment of memory based on the application’s performance. This function is not activated by default but can be easily turned on through environment variables or MSBuild properties – helping to balance application performance and memory usage. This evolution will be described in more detail later on.
The ability to run Microsoft .NET containers as non-root is now the default configuration, enhancing application security. The default container tag has been changed to “latest”, making containers easier to use in development. These changes aim to facilitate the secure and efficient use of .NET containers.
.NET 8 also introduces an environment variable for the User Identification (UID) of the non-root user, simplifying testing on Kubernetes. The default port has been changed from 80 to 8080, and a new environment variable (ASPNETCORE_HTTP_PORTS) has been added to simplify port changes. Additionally, container image tags for .NET 8 previews will no longer have the “-preview” suffix, and the new tags “8.0” and “8.0-<OS>” will be permanent and maintained throughout the life of .NET 8. These changes aim to improve the usability and security of .NET containers.
.NET 8 also introduces several significant improvements and new features in the area of serialisation, aiming to enhance flexibility and performance in serialisation and data manipulation.
The new version extends compatibility to include new numeric types such as Half, Int128, and UInt128, as well as data structures like Memory<T> and ReadOnlyMemory<T>. The platform has further improved the source-code generator to provide an experience closer to Native AOT compared to previous methods, adding support for types with mandatory and init-only properties. It also introduces more advanced converters and cleaner generated code formats.
Moreover, there is now robust support for serialising properties that are part of interface hierarchies, by introducing naming policies that facilitate conversion to formats like snake_case and kebab-case.
Deserialisation has been expanded to include read-only fields or properties, which was not possible before, and it offers an option to disable the reflection-based serialiser, ideal for applications using trimming and Native AOT features. Additional methods have been integrated into the JsonNode API for operations such as deep cloning and JSON comparison, and new features allow the inclusion of non-public members in the serialisation contract.
The release also includes extension methods for streaming IAsyncEnumerable<T> deserialisation, an extension method for modifying serialisation contracts, and new overloads for JSON content creation that align with code trimming and source-code generation security guidelines.
As briefly mentioned, .NET 8 introduces a feature to dynamically modify the memory limit, ideal for cloud service environments with changing demands. To maximise cost efficiency, services can now scale the consumed resources according to demand variations. When there is a decrease in need, services have the option to reduce resource consumption by adjusting the memory limit downward.
In previous versions, the GC might not have recognised the new configuration, resulting in memory allocation above the adjusted limit. The new API RefreshMemoryLimit() addresses this issue by synchronising the GC with the updated memory limit.
However, there are constraints to consider:
- On 32-bit operating systems, .NET cannot set a new maximum heap limit if one does not already exist.
- The API may indicate a failure to update, which can occur if the memory reduction is excessive and does not leave room for effective GC operation. If this happens, it is advisable to perform an aggressive garbage collection with GC.Collect(GCCollectionMode.Aggressive) to reduce memory consumption before attempting the operation again.
- Additionally, increasing the memory limit beyond the initial capacity estimated by the Garbage Collector during initialisation may not result in the effective use of additional memory, even if the update process is successful.
Native AOT support
The Native AOT (Ahead of Time) feature was introduced in .NET 7, allowing the creation of a fully self-contained version of an application that eliminates the need for a runtime, as everything is compiled into a single file. In .NET 8, this functionality has been enhanced with support for x64 and Arm64 architectures on MacOS.
There has also been a significant reduction in the size of Native AOT applications on Linux, with a decrease of up to 50%. It is now possible to choose the optimisation preference between size and speed. By default, the compiler seeks a balance between fast code and reduced application size, but you can set the MSBuild property <OptimizationPreference> to specifically optimise for one or the other criterion. For more details, you can refer to the documentation on AOT deployment optimisation.
These are just some of the improvements in .NET 8. The continuous enhancement of the framework by Microsoft has been contributing to making it increasingly adopted by companies and more popular among developers.
The chart below demonstrates the growing trend of C# programming language usage, the most popular for .NET development: