Search  
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

Source:
Views:
2267

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.

Similar
Jan 25
Author: Dev·edium
A deep dive into Ahead-of-Time (AOT) compilation for optimized performance What is it? Traditionally, .NET languages like C# use Just-in-Time (JIT) compilation. In this process, the source code is initially compiled into Common Intermediate Language (CIL) code, a platform-agnostic code...
Mar 28
Author: Hilal Yazbek
gRPC is a powerful framework for working with Remote Procedure Calls. RPCs allow you to write code as though it will be run on a local computer, even though it may be executed on another computer. One of the key...
Jul 29
Author: C# Programming Obinna “Anderson” Asiegbulam
Introduction Open Data Protocol (OData) is a standard protocol for building and consuming RESTful APIs. It extends traditional REST-based data access techniques by providing a uniform way to expose, structure, and manipulate data. Originally developed by Microsoft, OData is widely...
Dec 25, 2023
Author: Binod Mahto
Testing coverage is the key part of any project development and Testing coverage is not only about the unit testing instead Integration Testing is extremely important to make sure entire system is unbroken & bug free with any change or...
Send message
Type
Email
Your name
*Message