What’s New in ASP.NET Core 9

.NET 9 is out! It brings a lot of new features and performance improvements. 

Let’s explore what ASP.NET Core 9 brings new to us.  There are many improvements, but I picked some practical and interesting ones. 

Minimal API

The Minimal API gains a performance boost, as you can see on the chart provided by Microsoft. 

But the most expressive is the memory allocation! It was reduced to 93%! It’s imposing. 

To achieve such results, there are a lot of improvements under the good:

  • The exception handling is 50% faster. The previous structured exception handling was removed. The new implementation is based on the Native AOT model.
  • The runtime uses more vectorization to leverage SIMD (Single Instruction, Multiple Data) operations.
  • Dynamic Profile Guided Optimization (PGO) has been updated to optimize more code patterns.
  • System.Text.Json internals were significantly optimized. Learn more about what’s new in System.Text.Json in .NET 9
  • LINQ common operations also got improvements. For example, the Take method is up to 10 times faster when the underlying collection is empty. 

And many more improvements.

OpenAPI

ASP.NET Core 9 removes Swashbuckle from the template.

The .NET team added support for OpenAPI document generation.

To use it, you have to install Microsoft.AspNetCore.OpenApi package.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.Run();

The AddOpenApi method registers the required dependencies. 

The MapOpenApi method registers OpenAPI endpoints.

You can find the generated OpenAPI document by the link /openapi/v1.json.

If you like Swagger, you can add it as a separate package and configure it. 

app.UseSwaggerUi(c => c.DocumentPath = "/openapi/v1.json");

To learn about more OpenAPI features, visit the Generate OpenAPI documents.

Keyed Services in Middleware

The Keyed Services were introduced in .NET 8. 

However, you couldn’t use them in the Middleware.

ASP.NET Core 9 fixes the issue. 

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddKeyedSingleton<MySingleton>("singleton");
builder.Services.AddKeyedScoped<MyScoped>("");

var app = builder.Build();
app.UseMiddleware<MyMiddleware>();
app.Run();

internal class MyMiddleware
{
    private readonly RequestDelegate _next;

    public MyMiddleware(RequestDelegate next,
        [FromKeyedServices("singleton")] MySingleton service)
    {
        _next = next;
    }

    public Task Invoke(HttpContext context,
        [FromKeyedServices("scoped")]
                MyScoped scopedService) => _next(context);
}

public class MySingleton
{ }

public class MyScoped
{ }

Disabling Metrics

ASP NET Core 9 allows the disabling of HTTP metrics and the non-recording of values for specific endpoints and requests. 

For instance, automated systems check the Health endpoint, so recording metrics for it is not particularly helpful.

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

app.MapHealthChecks("/health").DisableHttpMetrics();

app.Run();

Developer Exception Page

The ASP.NET Core displays the developer exception page when unhandled exceptions occur while developing. 

The developer exception page now shows the endpoint metadata. 

StatusCodeSelector

ASP NET Core 8 introduced the IExceptionHandler.

The issue was that the default exception handler always set the response status code to 500 (Internal Server Error). 

ASP NET Core 9 introduces the new option StatusCodeSelector, which allows you to choose the status code based on the exception.

app.UseExceptionHandler(new ExceptionHandlerOptions
{
  StatusCodeSelector = ex => is TimeoutException
    ? StatusCodes.Status503ServiceUnavailable
    : StatusCodes.Status500InternalServerError
});

TypedResults.InternalServerError

The TypedResults class offers a convenient way to return strongly typed, status code-based responses from minimal APIs. Now, it supports a method for creating an Internal Server Error (500) response. 

app.MapGet("/", () => TypedResults.InternalServerError("Something went wrong!"));

HybridCache

HybridCache is still in preview but will be fully released after .NET 9.0 in a future minor release of .NET Extensions.

The new HybridCache is a better version of the IDistributedCache and IMemoryCache interfaces, making adding cache code more straightforward.

If you used IDistributedCache, you know that before setting a value in the cache, you have to deserialize the object to bytes of JSON — the same for getting value from the cache. Also, when many threads concurrently hit the cache, you can get problems with cache misses. 

The new HybridCache does all the required work for you. It also implements “Stampede protection,” which refers to techniques used in software systems to prevent multiple processes, threads, or servers from overwhelming a resource or performing redundant work when accessing shared data or resources simultaneously.

To add HybridCache to your application, add the line. 

builder.Services.AddHybridCache();

Then, usage of the cache is simple. 

public class WeatherForecastService(HybridCache cache)
{
    public async Task<WeatherForecast> GetWeatherForecast
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"weatherforecast:{name}:{id}", // Unique key.
            async cancel => await GetWeatherForecastFromApi(name, id, cancel),
            cancellationToken: token
        );
    }

    private async Task<WeatherForecast> GetWeatherForecastFromApi(
        string name, int id, CancellationToken cancel)
    {
        // Simulate a call to an external API.
        return new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now),
            25,
            null
        );
    }
}

Summary

ASP.NET Core 9 brings many improvements and features. One impressive one is reducing memory allocation in the Minimal API. ASP.NET Core 9 supports OpenAPI generation. Also, it has many handy small improvements that make developing APIs better.

And shortly, we’ll get a new, better HybridCache to work with a cache.

It’s not all features and improvements. Also, Blazor and SignalR get some upgrades. Read more here

Scroll to Top