Read time: 4 minutes

Today I want to talk about .NET 8 and why I think it is the best version of .NET to build microservices.

Microservices are the best way to build cloud-ready systems at scale, and they are especially popular across large organizations that build big and complex systems across multiple teams.

But as with every distributed system, building microservices is hard. Lots of things to worry about, like resilience, deployment, observability, and more.

Fortunately, .NET 8 introduced an impressive set of features that make building microservices with .NET easier than ever.

Let’s dive in.


1. Resilient app development

Resiliency is the ability of an app to recover from transient failures and continue to function.

This is a key feature of microservices because they are essentially distributed systems, and failures are inevitable.

In the past, you had to import external libraries like Polly to add resilience to your microservices, but with .NET 8 there’s a much easier way.

You can install the new Microsoft.Extensions.Http.Resilience NuGet package into your microservice and then you can do things like this:

builder.Services.AddHttpClient<GamesClient>(client =>
{
    client.BaseAddress = new("http://localhost:5115");
})
.AddStandardResilienceHandler();

The AddStandardResilienceHandler() call adds the standard resilience handler, which uses multiple resilience strategies stacked atop one another, with default options to send the requests and handle any transient errors.

Specifically, it will add default strategies for:

  • Rate limiting
  • Total request timeout
  • Retries
  • Circuit breaking
  • Timeouts per retry

To learn more, check the official docs over here or my YouTube video.


2. Container tooling

Containers are the most popular way to package cloud applications consistently so that they can be deployed anywhere.

They are a fundamental technology for microservices because they allow you to package each microservice into its own container, which can then be deployed and scaled independently.

Native container tooling was introduced in .NET 7, but in .NET 8 it was improved so that is it now easier than ever to generate Docker container images with the .NET CLI.

For instance, this single command:

dotnet publish /t:PublishContainer -p ContainerImageTag=1.0.0 \
-p ContainerRegistry=gamestore.azurecr.io

Will turn your .NET microservice into a Docker container image, tag it and push it to your Azure Container Registry. No Dockerfile needed!

I created a tutorial based on the .NET 7 container support over here, but for the latest on .NET 8 support check this official doc.


3. Native AOT

Native AOT (Ahead-Of-Time) compilation is the process of producing a self-contained app that has been ahead-of-time (AOT) compiled into native code.

Apps that are published using AOT are smaller in size, use less memory, and can start faster.

This quality is essential for microservices because they are often deployed as containers that are expected to start quickly and use as few resources as possible.

To enable Native AOT for your .NET microservice you’ll need to add the PublishAot property to your project file:

<PropertyGroup>
  <PublishAot>true</PublishAot>
</PropertyGroup>

And then you’ll use the new CreateSlimBuilder method, along with the JSON serializer source generator to define your HTTP APIs, like in this example:

var builder = WebApplication.CreateSlimBuilder(args);

builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});

var app = builder.Build();

Game[] games =
[
    new (1,"Street Fighter II",19.99M,new DateOnly(1992, 7, 15)),
    new (2,"Final Fantasy XIV",59.99M,new DateOnly(2010, 9, 30)),
    new (3,"FIFA 23",69.99M,new DateOnly(2022, 9, 27))
];

app.MapGet("games", () => games);

app.Run();

public record class Game(int Id, string Name, decimal Price, DateOnly ReleaseDate);

[JsonSerializable(typeof(Game[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}

CreateSlimBuilder() will ensure that only the essential features are enabled by default, while the JSON serializer source generator is needed to generate serialization code at build time (required for Native AOT compilation).

More info on Native AOT over here.


4. Observability and OpenTelemetry

Observability is the ability to monitor your application so that you can tell how well it is performing and to detect potential problems before they become larger.

This is incredibly important for microservices because it can be hard to understand what is happening with them as they interact with each other and with other external services in the cloud.

And that’s where OpenTelemetry comes in. It is a cross-platform, open standard for collecting and emitting telemetry data.

And .NET has built-in support for OpenTelemetry, so you can easily add it to your microservices to collect and emit telemetry data.

For instance, you can enable OpenTelemetry and export telemetry data to Azure Monitor Application Insights by installing one NuGet package:

dotnet add package Azure.Monitor.OpenTelemetry.AspNetCore

And then adding this one line of code to your microservice Program.cs file:

builder.Services.AddOpenTelemetry().UseAzureMonitor();

That is enough to get Logging, Metrics and Distributed Tracing (the 3 pillars of observability) for your microservice in Azure.

That was all available already in .NET 7, but in .NET 8 the team added tons of new useful metrics to ASP.NET Core, and they even created Grafana dashboards that are open source on GitHub so you can get something like this for your app:

To learn more, you can check my previous article over here, this YouTube video or the official docs here.


5. .NET Aspire

.NET Aspire is an opinionated, cloud-ready stack for building observable, production-ready, distributed applications.

It is available for .NET 8 applications and it essentially adds all the stuff I mentioned above (except for Native AOT) to your microservice by default, so you don’t have to worry about it.

And it adds a lot more stuff to improve the experience of building .NET microservices via a consistent, opinionated set of tools and patterns designed to build and run distributed apps.

It is still in preview at the time of writing, but the .NET team is heavily invested in it, it is getting a lot of amazing support from the community and its built-in dashboard is incredibly useful:

To learn more about .NET Aspire check out my previous article here and my YouTube videos here and here.


Summary

.NET 8 is the best version of .NET to build microservices. In fact, it may be the best platform to build microservices, period.

It has everything you need to build resilient, scalable, observable microservices that can be deployed anywhere, and it is incredibly easy to use.

If you are building microservices with .NET, and you are not using .NET 8, it is definitively time to upgrade.



Whenever you’re ready, there are 3 ways I can help you:

  1. ​Building Microservices With .NET:​ The only .NET backend development training program that you need to become a Senior .NET Backend Engineer.

  2. ASP.NET Core Full Stack Bundle: A carefully crafted package to kickstart your career as an ASP.NET Core Full Stack Developer, step by step.

  3. Promote yourself to 15,000+ subscribers by sponsoring this newsletter.