Back to blog
cloudbeginner

.NET Aspire — Cloud-Native Apps Without the Boilerplate

Discover .NET Aspire: a new opinionated stack for building observable, production-ready .NET cloud applications. Learn the App Host, service discovery, components, and the dev dashboard.

Asma HafeezApril 17, 20264 min read
dotnetaspirecloud-nativemicroservicescsharp
Share:š•

.NET Aspire

.NET Aspire is an opinionated, cloud-ready stack for building distributed .NET applications. It solves the boilerplate problem: service discovery, health checks, telemetry, and local orchestration — configured once, works everywhere.


What Problem Does Aspire Solve?

Building a distributed app typically means manually wiring up:

  • Service discovery (how does Service A find Service B?)
  • Connection strings (hard-coded or environment variables?)
  • Distributed tracing (OpenTelemetry, but how to configure?)
  • Health checks (each service defines its own)
  • Local dev (Docker Compose, manual ports, remembering which service to start first)

Aspire handles all of this from a single App Host project.


The Three Aspire Projects

MyApp.AppHost        — orchestrates everything; defines the distributed app
MyApp.ServiceDefaults — shared defaults: telemetry, health checks, service discovery
MyApp.ApiService     — your actual service (references ServiceDefaults)
MyApp.Web            — Blazor/React frontend (references ServiceDefaults)

Setup

Bash
dotnet workload install aspire

dotnet new aspire-starter -n MyApp

Or add Aspire to an existing solution:

Bash
dotnet new aspire-apphost -n MyApp.AppHost
dotnet new aspire-servicedefaults -n MyApp.ServiceDefaults

App Host — Orchestrating Services

C#
// MyApp.AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);

// Add a Redis cache
var cache = builder.AddRedis("cache");

// Add a PostgreSQL database
var db = builder.AddPostgres("postgres")
                .AddDatabase("mydb");

// Add the API service, inject the cache and DB as dependencies
var api = builder.AddProject<Projects.MyApp_ApiService>("api")
                 .WithReference(cache)
                 .WithReference(db);

// Add the frontend, inject the API endpoint
builder.AddProject<Projects.MyApp_Web>("webfrontend")
       .WithReference(api)
       .WithExternalHttpEndpoints();

builder.Build().Run();

When you run the AppHost, Aspire starts Redis and PostgreSQL in Docker, starts both .NET projects, and wires up all connection strings automatically.


Service Defaults — Shared Configuration

C#
// MyApp.ServiceDefaults/Extensions.cs (generated)
public static class Extensions
{
    public static IHostApplicationBuilder AddServiceDefaults(
        this IHostApplicationBuilder builder)
    {
        // OpenTelemetry — traces, metrics, logs
        builder.ConfigureOpenTelemetry();

        // Health checks — /health and /alive endpoints
        builder.AddDefaultHealthChecks();

        // Service discovery
        builder.Services.AddServiceDiscovery();
        builder.Services.ConfigureHttpClientDefaults(http =>
        {
            http.AddServiceDiscovery();
            http.AddStandardResilienceHandler(); // retries + circuit breaker
        });

        return builder;
    }
}

Every service calls builder.AddServiceDefaults() — one line gets you telemetry, health checks, and resilient HTTP clients.


Service Discovery in Action

C#
// In the frontend (MyApp.Web/Program.cs)
builder.AddServiceDefaults();

// Register a typed HTTP client pointing to the API by name
builder.Services.AddHttpClient<ApiClient>(
    client => client.BaseAddress = new Uri("https+http://api")); // "api" matches AppHost name

No hard-coded URLs. Aspire injects the actual address at runtime based on whether you're in local dev, Docker, or Kubernetes.


Aspire Components

Aspire provides pre-built integration packages that configure services with best practices baked in:

Bash
dotnet add package Aspire.StackExchange.Redis
dotnet add package Aspire.Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Aspire.Azure.Storage.Blobs
dotnet add package Aspire.Azure.Messaging.ServiceBus
C#
// In your service (Program.cs)
builder.AddServiceDefaults();

// Redis — auto-configured, connection string injected by AppHost
builder.AddRedisDistributedCache("cache");

// PostgreSQL + EF Core — auto-configured
builder.AddNpgsqlDbContext<AppDbContext>("mydb");

Each component wires up health checks, telemetry, and retry policies for that specific service.


The Dev Dashboard

When you run the AppHost, a local dashboard opens at http://localhost:15888:

Dashboard shows:
• All running resources (services, containers, databases)
• Structured logs from every service in one view
• Distributed traces — see a request as it flows through multiple services
• Metrics — CPU, memory, request rate, error rate
• Environment variables and connection strings for each service

This is the same observability you'd have in production — available on day one of local development.


Deploying with Aspire

Bash
# Deploy to Azure Container Apps (ACA)
dotnet tool install -g aspire.cli

aspire deploy

Aspire generates the Azure Container Apps YAML and deploys all services, automatically provisioning managed Redis (Azure Cache for Redis) and PostgreSQL (Azure Database for PostgreSQL) to replace the local Docker containers.


Key Takeaways

  1. App Host is the single source of truth for your distributed app — services, databases, and their connections
  2. Service Defaults gives every service OpenTelemetry, health checks, and resilient HTTP clients in one line
  3. Service discovery replaces hard-coded URLs — services find each other by name
  4. Aspire components are opinionated integrations that include health checks and telemetry out of the box
  5. The dev dashboard gives production-grade observability locally — traces, logs, and metrics from day one

Enjoyed this article?

Explore the learning path for more.

Found this helpful?

Share:š•

Leave a comment

Have a question, correction, or just found this helpful? Leave a note below.