.NET Aspire and Cloud-Native Development

This section documents ASP.NET Core on .NET 10 (LTS), the current release — the minimal hosting model, the middleware pipeline, dependency injection, Minimal APIs, MVC & Razor Pages, Blazor with the current render modes, SignalR and gRPC, EF Core, ASP.NET Core Identity and policy-based authorization, output caching, rate limiting, and Native-AOT-aware building — as described by the official documentation at Microsoft Learn, which is the reference these pages are written and verified against.

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. .NET ships a major release every November and its APIs continue to evolve: the examples here target .NET 10 / C# 14.

This section’s bibliography lists the reference material consulted while preparing these pages.

NET Aspire is an opinionated stack for building and locally running distributed applications — an

ASP.NET Core API, a Blazor front end, a database, a cache, and a message broker, wired together, observed, and started with one command.

The AppHost project

dotnet new aspire-apphost (or the full aspire starter template) scaffolds an AppHost project: an executable .csproj whose Program.cs declares every resource the distributed application needs and how they connect:

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedis("cache");
var db = builder.AddPostgres("postgres").AddDatabase("ordersdb");

var api = builder.AddProject<Projects.OrdersApi>("orders-api")
    .WithReference(db)
    .WithReference(cache);

builder.AddProject<Projects.Web>("web")
    .WithReference(api)
    .WithExternalHttpEndpoints();

builder.Build().Run();

Running the AppHost starts every referenced project and container resource together, opens the Aspire dashboard, and injects each resource’s connection details into the projects that reference it. See .NET Aspire overview and .NET Aspire orchestration overview.

The ServiceDefaults project

A shared ServiceDefaults project (also scaffolded by the template) centralizes the cross-cutting setup every service in the solution wants — OpenTelemetry, health checks, service discovery, and resilient HttpClient defaults:

// ServiceDefaults/Extensions.cs
public static class Extensions
{
    public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder)
        where TBuilder : IHostApplicationBuilder
    {
        builder.ConfigureOpenTelemetry();
        builder.AddDefaultHealthChecks();
        builder.Services.AddServiceDiscovery();
        builder.Services.ConfigureHttpClientDefaults(http =>
        {
            http.AddServiceDiscovery();
            http.AddStandardResilienceHandler();   // see
                // xref:web/aspnet/core/http-client-and-resilience.adoc[HTTP Client and Resilience]
        });
        return builder;
    }
}
// OrdersApi/Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();

Every project referenced by the AppHost calls AddServiceDefaults() once, so telemetry, health checks, and resilient outbound HTTP calls are consistent across the whole distributed app instead of configured per-project. See .NET Aspire service defaults.

Resources and references

An Aspire resource is anything the app depends on — another project, a container (Redis, PostgreSQL, RabbitMQ), or an external endpoint. WithReference(resource) on a project injects that resource’s connection information (connection string, endpoint URL) into the referencing project’s configuration at startup, so the referencing code just reads IConfiguration/a typed client as usual, with the actual value supplied by the AppHost rather than an appsettings.json file.

Service discovery

Projects that reference each other resolve one another by their logical name ("orders-api" above), not a hardcoded host/port — AddServiceDiscovery() (part of ServiceDefaults) resolves https://orders-api to the actual running endpoint, which differs between local runs (a localhost port Aspire allocates) and a deployed environment (a real service address), with no code change:

builder.Services.AddHttpClient<OrdersApiClient>(c => c.BaseAddress = new Uri("https://orders-api"));

The dashboard

The Aspire dashboard (opened automatically when the AppHost runs) gives one place to see the whole distributed app while developing:

  • Structured logs — aggregated across every resource, filterable by resource and level.

  • Traces — distributed traces spanning multiple services for one logical request, built on the same OpenTelemetry data covered in Error Handling, Logging, and Observability.

  • Metrics — live charts per resource (request rate, duration, custom System.Diagnostics.Metrics instruments).

This replaces manually juggling multiple terminal windows and separately wiring up an OpenTelemetry collector just to see what a local multi-service run is doing. See .NET Aspire dashboard overview.

Integrations

An Aspire integration is a NuGet package pairing an AppHost-side resource type with a client-side Add<Resource>Client() extension preconfigured with health checks, telemetry, and resilience for that specific dependency:

// AppHost
var postgres = builder.AddPostgres("postgres").AddDatabase("ordersdb");

// OrdersApi
builder.AddNpgsqlDbContext<OrdersDbContext>("ordersdb");   // Aspire.Npgsql.EntityFrameworkCore.PostgreSQL

Official integrations cover PostgreSQL, Redis, RabbitMQ, SQL Server, MongoDB, Kafka, and more, each following the same "AppHost declares the resource, client project adds the matching integration" shape. See .NET Aspire integrations overview.

Local orchestration vs. deployment

Aspire’s AppHost is a local development and orchestration tool — it is not itself a production hosting runtime. Deploying an Aspire-built app means translating its resource graph to a real target:

  • azd (Azure Developer CLI) reads the AppHost’s resource graph and provisions/deploys matching Azure resources (Container Apps, Azure Database for PostgreSQL, Azure Cache for Redis, …​).

  • A manifest export (dotnet run --project AppHost — --publisher manifest) produces a target-agnostic JSON description of the resource graph other tooling (including third-party deployment tools) can consume.

See .NET Aspire deployment overview and Deployment for the underlying container/hosting mechanics being deployed to.

Aspire vs. Docker Compose / Kubernetes

Tool Role

.NET Aspire AppHost

Describes the resource graph in C#, drives local multi-project/container startup with service discovery and one dashboard; not a production orchestrator itself.

Docker Compose

A container-only, YAML-described local orchestration tool — Aspire can run containers too, but also directly launches .NET projects (no Dockerfile needed for local iteration) and adds the dashboard/telemetry/service-discovery layer Compose does not provide out of the box.

Kubernetes

A production container orchestrator — Aspire is not a Kubernetes alternative; an Aspire app is typically deployed to Kubernetes (or another target) rather than run there via the AppHost.

Aspire and Docker Compose/Kubernetes are complementary at different stages: Aspire for the local inner-loop experience, Compose/Kubernetes (or a cloud-native platform reached via azd) for how the same services actually run in production.