Поиск  
Always will be ready notify the world about expectations as easy as possible: job change page
Feb 29

A dive into .NET 8 native AOT and efficient web development

Автор:
Источник:
Просмотров:
2552

Introduction

With the release of .NET 8, Microsoft takes a significant stride forward, introducing the native Ahead-of-Time (AOT) compilation for ASP.NET Core. This advancement not only enhances application performance but also simplifies the development process, marking a new era in the .NET ecosystem.

The emergence of native AOT in .NET 8

The introduction of native AOT in .NET 8 is a game-changer for web developers. This technology compiles .NET code directly into native code, bypassing the need for Just-In-Time (JIT) compilation at runtime. The result? Faster startup times, reduced memory footprint, and overall improved application performance, especially crucial for high-traffic web APIs and microservices.

Exploring the ASP.NET Core Web API (native AOT) project template

.NET 8 introduces a new project template specifically designed for native AOT — the ASP.NET Core Web API (native AOT) project template. This template, identified by the short name ‘webapiaot’, comes with AOT publish enabled by default. It’s tailored for developers looking to leverage the full potential of AOT compilation right from the onset of their project. Two new features in this update is the CreateSlimBuilder() and CreateEmptyBuilder() method.

The CreateSlimBuilder method: optimizing for efficiency

CreateSlimBuilder method is a testament to Microsoft’s commitment to efficient development. It initializes the WebApplicationBuilder with only the essential ASP.NET Core features needed to run an application. This approach not only streamlines the development process but also ensures that the applications are lightweight and high-performing. Key features included in the CreateSlimBuilder method are:

  • JSON file configuration for appsettings.json and appsettings.{EnvironmentName}.json, enabling robust and flexible configuration management.
  • Integration of User secrets configuration, enhancing security in development environments.
  • Built-in Console logging, facilitating straightforward debugging and monitoring.
  • Comprehensive Logging configuration, providing developers with critical insights into application behavior.
var builder = WebApplication.CreateSlimBuilder(args);

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Yet, the CreateSlimBuilder method's ascetic approach omits the traditional Startup.cs file, necessitating explicit configuration by developers. It also strips out the EventLog, Debug providers, and EventSource host—components that must be manually included if needed. Crucially, there's no out-of-the-box support for IIS, HTTPS, HTTP3, or the full suite of Kestrel server configurations, calling for deliberate additions to fortify communication security and server robustness.

These can be explicitly added to your configuration. For instance, see the following example for how to implement these customizations.

using Microsoft.AspNetCore.Routing.Constraints;

var builder = WebApplication.CreateSlimBuilder(args);

//http3 customization
builder.WebHost.UseQuic();

//Https customization
builder.WebHost.UseKestrelHttpsConfiguration();

//Regex customization
builder.Services.AddRouting().Configure<RouteOptions>(x =>
{
    x.SetParameterPolicy<RegexInlineRouteConstraint>("Regex");
});

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

The CreateEmptyBuilderMethod: customization in its purest form

.NET 8’s CreateEmptyBuilder method is a testament to customization, offering developers a blank slate to craft bespoke, small-scale applications. It's the epitome of simplicity and autonomy, where only the selected components find a place.

var builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions
{
    Args =args
});

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

To ensure the application functions correctly, each component must be configured manually. Attempting to execute the above code without the necessary configurations will result in errors.

using Microsoft.AspNetCore.Routing.Constraints;

var builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions
{
    Args = args
});
builder.WebHost.UseKestrelCore();
builder.Services.AddRoutingCore();

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Benchmark conclusion: assessing Builder methods in .NET 8

using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Routing.Constraints;
using System.Collections.Generic;

namespace NewAppTypes
{
    [MemoryDiagnoser]
    public class BenchMarks
    {
        public string[]? Args { get; private set; }

        [Benchmark]
        public void CreateBuilder()
        {
            var builder = WebApplication.CreateBuilder(Args);
            var app = builder.Build();
            builder.WebHost.UseUrls("http://*:80", "https://*.443");


            app.MapGet("/", () => "Hello World!");

        }

        [Benchmark]
        public void CreateSlimBuilder()
        {
            var builder = WebApplication.CreateSlimBuilder(Args);

            //http3 customization
            builder.WebHost.UseQuic();

            //Https customization
            builder.WebHost.UseKestrelHttpsConfiguration();

            //Regex customization
            builder.Services.AddRouting().Configure<RouteOptions>(x =>
            {
                x.SetParameterPolicy<RegexInlineRouteConstraint>("Regex");
            });

            var app = builder.Build();
            builder.WebHost.UseUrls("http://*:80", "https://*.443");
            app.MapGet("/", () => "Hello World!");

        }

        [Benchmark]
        public void CreateEmptyBuilder()
        {
            var builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions
            {
                Args = Args
            });
            builder.WebHost.UseKestrelCore();
            builder.Services.AddRoutingCore();

            var app = builder.Build();
            builder.WebHost.UseUrls("http://*:80", "https://*.443");
            app.MapGet("/", () => "Hello World!");

        }

    }
}

Benchmark results
Benchmark results

The benchmark tests reveal insightful data on their performance. From the results, we observe the following:

  • CreateBuilder method: This standard method for initializing a web application shows a mean execution time of 2,682.3 microseconds (us) with an allocation of approximately 536.26 KB. This method sets up a complete web hosting environment with all default services and configurations. The execution time and memory allocation reflect this comprehensiveness.
  • CreateSlimBuilder method: The optimized CreateSlimBuilder method records a faster mean execution time of 1,604.4 us, around 40% quicker than the CreateBuilder method. It also allocates less memory, approximately 428.34 KB. This performance gain can be attributed to the reduced number of default services and configurations, which aligns with the method’s design to provide a more streamlined startup.
  • CreateEmptyBuilder method: The most minimalistic approach, CreateEmptyBuilder, showcases the fastest mean execution time of 121.3 us, which is substantially quicker than the other two methods. It also has the lowest memory footprint with just over 107.78 KB allocated. This highlights the method’s bare-bones initialization strategy, where only explicitly defined services and configurations are included.

The standard deviations indicate the variability in execution times across multiple runs, with CreateBuilder having the highest variability. This could be due to the larger number of components being loaded and configured, which may introduce more fluctuation in initialization time.

In terms of application development, these benchmarks suggest that CreateSlimBuilder and CreateEmptyBuilder offer significant performance advantages over the traditional CreateBuilder method. Developers should consider these options when performance is a critical factor, especially in environments where startup time and memory efficiency are paramount.

However, it is important to note that these performance improvements come with trade-offs in functionality. While CreateEmptyBuilder provides the fastest startup and the lowest resource consumption, it requires developers to manually configure all required services, which could increase development complexity and time. CreateSlimBuilder offers a middle ground, with some default configurations provided while still allowing for a leaner application setup.

Conclusion

The selection of a builder method in .NET 8 is not merely a technical decision but a strategic one, influenced by the project’s unique demands. The benchmarks provide a quantitative foundation for this choice, ensuring that developers are well-equipped to make decisions that align with their performance targets and development philosophies.

Похожее
Apr 12, 2023
Author: Jaimin Soni
HTTP/3 is the latest version of the HTTP protocol, built on top of the QUIC transport protocol. It offers several advantages over its predecessors, including faster and more reliable connections, improved security, and reduced latency. In this article, we will...
Jul 22
Author: Gabriele Tronchin
Introduction One common way to speed up our applications is by introducing a cache. Typically, the first option that comes to mind is using a MemoryCache (RAM) to save some data in order to speed up retrieval. This approach works...
Jul 22
Author: Ankit Sahu
Introduction In this article, we are going to discuss What Entity Framework is and How we can implement it in the .Net 8 project. This is a continuation of part 1, so if you are new to this article, please...
Dec 20, 2023
Author: Fiodar Sazanavets
You can run a single monolithic instance of a server application only if the number of clients accessing your application doesn’t exceed a couple of thousand. But what if you expect hundreds of thousands, or even millions, of clients to...
Написать сообщение
Тип
Почта
Имя
*Сообщение