Isaac.

.NET Aspire Distributed Applications

Simplify orchestration of distributed .NET applications.

By EMEPublished: February 20, 2025
dotnet aspireorchestrationdistributed systemsmicroservices

A Simple Analogy

.NET Aspire is like a conductor's score for your services. Define all services in one place, how they connect, and Aspire orchestrates them during development and guides production deployment.


What Is .NET Aspire?

.NET Aspire is a stack for building cloud-native distributed applications with built-in orchestration, observability, and configuration management.


Project Structure

MyDistributedApp/
├── MyDistributedApp.AppHost/          # Orchestration
├── MyDistributedApp.ServiceDefaults/  # Shared defaults
├── Api.Service/                        # API service
├── Worker.Service/                     # Background service
└── Db.Migrations/                      # Database migrations

Orchestration (AppHost)

// Program.cs
var builder = DistributedApplication.CreateBuilder(args);

// Add services
var apiServicePort = 5001;
var apiService = builder
    .AddProject<Projects.ApiService>("apiservice")
    .WithHttpEndpoint(port: apiServicePort, targetPort: 80);

var workerService = builder
    .AddProject<Projects.WorkerService>("workerservice");

// Add database
var postgres = builder
    .AddPostgres("postgres")
    .AddDatabase("appdb");

// Add message broker
var rabbitmq = builder
    .AddRabbitMQ("rabbitmq")
    .WithManagementPlugin();

// Connect services to resources
apiService
    .WithReference(postgres)
    .WithReference(rabbitmq);

workerService
    .WithReference(postgres)
    .WithReference(rabbitmq);

// Add dashboard
builder.AddProject<Projects.WebApi>("webapi")
    .WithReference(apiService);

var app = builder.Build();
await app.RunAsync();

Service Implementation

// ApiService/Program.cs
var builder = WebApplication.CreateBuilder(args);

// Use Aspire service defaults
builder.AddServiceDefaults();

// Add services
builder.Services.AddScoped<IOrderService, OrderService>();

var app = builder.Build();

// Use Aspire defaults (middleware)
app.UseServiceDefaults();

app.MapPost("/api/orders", async (CreateOrderRequest req, IOrderService service) =>
{
    return await service.CreateAsync(req);
});

app.Run();

// ServiceDefaults/Extensions.cs
public static class Extensions
{
    public static IServiceCollection AddServiceDefaults(this IServiceCollection services)
    {
        // Add health checks
        services.AddHealthChecks()
            .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
        
        // Add observability
        services.AddOpenTelemetry()
            .WithTracing(tracing => tracing
                .AddAspNetCoreInstrumentation()
                .AddHttpClientInstrumentation());
        
        return services;
    }
    
    public static WebApplication UseServiceDefaults(this WebApplication app)
    {
        app.MapHealthChecks("/health");
        app.UseOpenTelemetryPrometheusScrap();
        return app;
    }
}

Database Integration

// AppHost
var postgres = builder
    .AddPostgres("postgres", password: "password")
    .AddDatabase("appdb");

// In service
builder.Services.AddDbContext<AppDbContext>((sp, options) =>
{
    var connection = sp.GetRequiredService<IConfiguration>().GetConnectionString("appdb");
    options.UseNpgsql(connection);
});

Configuration Management

// AppHost
var apiKey = builder.AddParameter("ApiKey");

var apiService = builder
    .AddProject<Projects.ApiService>("apiservice")
    .WithEnvironment("API_KEY", apiKey);

// In service
var apiKey = app.Configuration["API_KEY"];

Practical Example

# Full distributed app
Projects:
  - ApiService
  - WorkerService
  - Dashboard
  
Resources:
  - PostgreSQL database
  - RabbitMQ message broker
  - Redis cache
  - Open Telemetry collector
  
Networking:
  All services can reference each other by name
  Environment variables injected automatically
  
Observability:
  Logs aggregated
  Traces collected
  Metrics exposed

Best Practices

  1. Use AppHost for orchestration: Central place for topology
  2. Implement health checks: Enable liveness/readiness
  3. Use service defaults: Shared configuration
  4. Add observability: Traces, logs, metrics
  5. Document dependencies: Clarify service relationships

Related Concepts

  • Docker Compose (simpler)
  • Kubernetes (production)
  • Service mesh for advanced networking
  • GitOps for declarative deployment

Summary

.NET Aspire streamlines building and orchestrating cloud-native distributed applications. Define your entire application topology in code with automatic service discovery and observability.