Why should I use .NET Aspire?

Sometimes I hear, “.NET Aspire is interesting for DevOps, but not so for developers.”, “It’s hard to integrate this with our existing environment”.

Whether you’re a developer looking to streamline your local development setup or a DevOps engineer aiming to optimize deployment pipelines, .NET Aspire offers tools and integrations that cater to both worlds. From pulling necessary services with Docker to enabling structured logging, distributed tracing, and metrics collection, .NET Aspire empowers teams to build robust, scalable, and maintainable applications with minimal effort.

Let me answer this here – What do you get out of .NET Aspire without the deployment aspect. This article explores what needs to be done to add .NET Aspire functionality to existing applications without the built-in Visual Studio feature – adding it step by step which shows the same application can be deployed to an existing environment.

Why .NET Aspire?

Infrastructure for development

When setting up a development machine, we often need SQL Server, other databases, and caching solutions like Redis. It takes time to install the infrastructure for the developer system, and developers need to learn about all the parts involved. Just having the requirement of Docker (using Docker Desktop or Podman), .NET Aspire pulls all the services needed, and they are automatically connected with visible relationships.

Many Azure resources nowadays offer emulators running within Docker – e.g., Azure Cosmos DB or Azure Event Hub. Not all are available yet, but .NET Aspire makes it easy to create resources within Azure, which can happen just while debugging the application!

Defining an app-model with .NET Aspire makes this easy – everything is here as required to have the application with all the services required as needed.

Using .NET Aspire integrations, they already know about the folders that need to be mapped to keep the state persistent with a Docker volume, prepare a database by using EF Core migrations, or passing SQL scripts to initialize.

Resource usage easily visible while developing

While developing, using .NET Aspire, you can easily monitor the consumption of the solution, check memory usage, monitor how often services are invoked, and compare timings between accessing the database or using a cache.

When I hear about “we already have tests running with CI/CD which return information about issues with memory usage” – this is really great! Many companies don’t have this in place yet. However, when you see this information immediately at the time while working on the feature, you can react immediately instead of learning about issues a day later.

.NET Aspire is great to learn about the behavior of the solution during development, to monitor it and understanding issues.

Deploying the application with .NET Aspire

.NET Aspire also helps with deploying. Deploy to Microsoft Azure? Use Kubernetes? Running the application with a simple Docker Compose?

Many companies are using Internet Information Server (IIS) to run your Web services and Web applications. The App Host project does not create a binary that’s deployed. This project is only used while developing, and to create artifacts for deployment.

It’s not required to use .NET Aspire for deployment. You can still deploy the Web applications and services as you are used to, they are still normal .NET applications (and yes, you can integrate non-.NET applications as well).

Using the new Aspire CLI (currently in preview), it’s becoming even easier to deploy using .NET Aspire. Publishers can be configured with the app model, which allows creating publishing artifacts for Microsoft Azure, Kubernetes, and Docker Compose. Other publishers will follow.

You don’t need to use every feature from .NET Aspire!

While .NET Aspire offers several areas of improvement, it’s not necessary to use all of them. You can enhance your solutions incrementally. What are the actual the pain points you have creating your solution? What could be improved? This should be where to put the focus to.

Using existing solutions, what are the steps that can be done to integrate .NET Aspire?

Let’s get into first steps to add .NET Aspire to an existing project.

Update a project to use .NET Aspire

While it’s easy to add .NET Aspire to an existing project with Visual Studio (select the project in the solution explorer, and select Add | .NET Aspire Orchestrator support, here we’ll do a more manual approach so you can easily see what can be done to get what features.

Create a “traditional” API project

First I’m creating a Web API without any .NET Aspire integration:

mkdir AspireSample
cd AspireSample
dotnet new webapi -o WeatherAPI -f net9.0

Running this project we can see weather information using a link defined with the launchsettings.json, adding weatherforecast, e.g. https://localhost:8765/weatherforecast

Next, let’s add the .NET Aspire AppHost

Create the .NET Aspire AppHost

To create this, I’m using the (currently in preview) .NET Aspire CLI. This tool can be installed with:

dotnet tool install aspire.cli -g --prerelease

Entering aspire new shows available templates:

.NET Aspire CLI new templates

Select aspire-apphost, and enter these options:

  • Project name: Weather.AppHost
  • Output path: ./Weather.AppHost
  • Select the .NET Aspire version (currently 9.2.1)

Next create a solution file, add the two projects, and add a reference to the AppHost project to reference the API project:

dotnet new solution -n Weather -f slnx
dotnet solution Weather.slnx add Weather.AppHost/Weather.AppHost.csproj
dotnet solution Weather.slnx add WeatherAPI/WeatherAPI.csproj
dotnet reference add WeatherAPI/WeatherAPI.csproj --project Weather.AppHost/Weather.AppHost.csproj

The API project is referenced by the AppHost to allow adding this project in a strongly-typed way to the app model

Weather.AppHost/Program.cs

var builder = DistributedApplication.CreateBuilder(args);
var weatherapi = builder.AddProject("weatherapi");
builder.Build().Run();

The AppHost project has the Aspire.AppHost.Sdk referenced, which adds the IsAppHost setting. With this extension for project references, a metadata is generated. The Projects namespace includes classes the reference the project file.

Weather.AppHost/Weather.AppHost.csproj

  <Sdk Name="Aspire.AppHost.Sdk" Version="9.2.1" />  

Instead of adding a reference to the API project, it’s also possible to use the non-generic AddProject method, and pass the file-path.

var weatherApi = builder.AddProject("weatherapi", "../WeatherAPI/WeatherAPI.csproj");

With just this information in place, starting the AppHost project starts the dashboard, and the API project.

Weather API resource in the dashboard

Checking the Console logs with the dashboard, the logs are shown:

Weather API console logs

Without a single change to the API project itself, startup can be customized by e.g. starting multiple replicas, and passing environment variables:

Weather.AppHost/Program.cs

var weatherapi = builder.AddProject("weatherapi")
    .WithReplicas(3)
    .WithEnvironment("MyEnv1", "some value");

Running the AppHost with this change, three instances of the API project are created, and the environment variable is set with these processes.

The dashboard views for structured logging, traces, and metrics don’t show any values yet – because the API project doesn’t forward this information to the dashboard yet. Let’s change this next.

Adding a Library for Service Defaults

Next some small changes are done to the API project. The functionality is added by using

Enter aspire new again, but select the aspire-servicedefaults template:

  • Project name: Weather.ServiceDefaults
  • Output path: ./Weather.ServiceDefaults

This library contains extension methods to enhance logging, distributed tracing, and metrics.

This library needs to be referenced from the API project:

dotnet solution Weather.slnx add Weather.ServiceDefaults/Weather.ServiceDefaults.csproj
dotnet reference add Weather.ServiceDefaults/Weather.ServiceDefaults.csproj --project WeatherAPI/WeatherAPI.csproj

Just small code changes are needed with the API to take advantage of this:

WeatherAPI/Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();

After creating the WebApplicationBuilder, invoke the AddServiceDefaults method defined by the new library. This configures the DI container.

With the middleware configuration, the extension method MapDefaultEndpoints from the ServiceDefaults library can be invoked:

WeatherAPI/Program.cs

app.MapDefaultEndpoints();

app.Run();

The MapDefaultEndpoints method just specifies health checks which are by default only used in development mode. For production mode you should change the configuration with the library.

With this configuration in place, the dashboard now shows structured logging, distributed tracing, and metrics data.

Structured logging

Distributed tracing

Metrics

While developing the application, having this information gives the advantage of finding issues early!

Just small changes are needed with the projects to use OpenTelemetry, and these changes usually don’t restrict already existing deployment options.

After the initial setup, the next steps are using service discovery, and adding database and service resources with .NET Aspire integrations. Then we’ll have the next advantages of .NET Aspire!

Service discovery can easily be configured with .NET Aspire by referencing APIs from applications which transparently forwards the links by using providers with your environments, no matter if Azure or Kubernetes is used. This works with IIS as well as service discovery includes a fallback to a configuration provider.

With .NET Aspire integrations, it’s easy to use different services such as many relational and NoSQL databases, REDIS, Keycloak and more!

For all this and more information about .NET Aspire, read my book Pragmatic Microservices with C# and Azure!

Summary

.NET Aspire simplifies development and deployment by providing a unified framework for managing infrastructure, monitoring resource usage, and integrating services. It allows developers to focus on building features while handling complex tasks like service discovery, distributed tracing, and metrics collection. With minimal changes to existing projects, developers can leverage powerful tools like structured logging and OpenTelemetry support.

Whether you’re deploying to Azure, Kubernetes, or using Docker Compose, .NET Aspire offers flexibility without locking you into specific deployment methods. Its incremental adoption approach ensures you can address pain points without overhauling your existing solutions.

Start small, enhance your projects step by step, and take advantage of .NET Aspire’s integrations with databases, caching solutions, and more. For a deeper dive, explore the resources linked in this article, including the book Pragmatic Microservices with C# and Azure.

Do you already use .NET Aspire? Share your experiences and thoughts in the comments!

For more information:

5 thoughts on “Why should I use .NET Aspire?

  1. While Aspire seems an interesting solution, as a Developer I am not allowed to use it unless it can be run within our local network only. Meaning, no dependencies to anything outside our 192.168.*.* network.

    Why? Because the company I work for is handling financial transactions. And while each transactions is small, the number of transactions is huge. So any code we write needs to be absolutely secure. And we do this quite well by keeping a lot of our services secure.

    But we also block out any external services, so Azure? Nope! AWS, Google, anything else? No, not allowed. We have physical servers in a local datacenter which run out services. And any service we create is tested to make sure it’s not calling out to some remote server.

    So I researched Aspire and it seems to be possible to use it on our local servers without any calls to external services. But I would lack some of the functionality it offers. And the constraints I have to deal with also means that proper training is required for the whole team, including any new developers who get hired.

    All in all, Aspire just doesn’t have what I need to use.

    Liked by 1 person

    1. Interesting constraints – and understandable. As you already researched, your requirements, no dependencies anything outside of your 192.168.*.* network shouldn’t be a problem using .NET Aspire.

      I assume you also use a local NuGet feed to get your packages. What services are you using? Are you using Windows systems with IIS, or do you run Docker containers in your local environment? When using Docker containers, developers also needs to be trained on all the different configurations for monitoring and specifying the correct folders to correctly map volumes. This is where .NET Aspire integrations help a lot, and not that much training is needed.

      I’m interested in what do you use to run your services on the developer system? What are you running besides Visual Studio to develop your applications? Databases, other services? Do you monitor resource usage using the integrated profiler? What pain points do you currently have in your environment?

      Like

      1. For NuGet we are limited in what we can use. The official Microsoft packages are considered safe. Any third-party package is considered risky. So we do use a local NuGet feed to just allow the packages that are deemed safe.

        As for the backend, we use both Windows Server with IIS and Ubuntu 24.04 Server with Nginx. As databases we use SQL Server, MySQL or PostgreSQL with SQLite for smaller, mobile applications. We have several high-end servers with many smaller, virtual machines running on them. These are layered within the network into special ‘DMZ’ environments. (With firewalls in-between.) For example, 192.168.20.* is for web applications/sites and 192.168.40.* for Web API’s that are called from these sites. With the database at 192.168.120.* and thus further away from the Internet.

        Our business is mostly for banks and financial instituter to create testcases for handling financial transactions through various channels. For this we have various smaller devices that are allowed to call external services, but with restrictions. The purpose is to mostly test if bank services are still online and working properly, which includes making small transactions and doing other actions to make sure these work. If something fails, then warnings and errors get triggered and the cause gets investigated.

        So we are monitoring our clients and their services. Can’t provide too many details about how we do that, but it involves a lot of hardware and virtual machines as we need to keep a lot of information very secure.

        As for development… There’s a lot that you can do with mock data and small applications and APIs. We develop database-agnostic so the development system might just use SQLite, as this allows the database to be within the project Git repository. Or we connect to the SQL Test Server through a VPN, which tends to be challenging. But most development is just small projects or maintenance on the larger projects.

        The main pain point that we have is that we have many smaller microservices and sites and keeping track of those all from within the network. With as main constraint the face that we’re dealing with layers of DMZ networks and the challenge that you can’t just access things in another DMZ layer. So we might need an Azure host per DMZ. And probably per client too, as we have several dozens of clients, for whom we have set up separated hosting environments.

        Liked by 1 person

  2. Thanks for your detailed answer!

    It looks so far you’ve made it without Docker. While you have SQL Server, MySQL, PostgreSQL, and SQLite in production, all your code is database-agnostic, sometimes you need to connect to SQL Server through a VPN.

    With Docker, you could easily run your application in the developer environment with all these different databases, including SQL Server. And .NET Aspire would make this easy to do.

    With the main pain point, and that many smaller microservices and sites in layers of DMZ networks: what do you use for logging and metrics currently? With one of my clients, each DMZ contains a log collector locally, which forwards logs to a central aggregator within a private DMZ. A central aggregator might not be allowed in your scenario. Do all clients also have separate physical systems?

    The .NET Aspire dashboard offers a great view which originally was only meant to be used during development. Now it can be used in production as well, but you need other software to store the information.

    Like

Leave a reply to Christian Nagel Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.