Isaac.

cloud

.NET Aspire Distributed Applications

Simplify orchestration of distributed .NET applications.

By Emem IsaacFebruary 10, 20243 min read
#dotnet aspire#orchestration#distributed systems#microservices
Share:

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.

Share:

Written by Emem Isaac

Expert Software Engineer with 15+ years of experience building scalable enterprise applications. Specialized in ASP.NET Core, Azure, Docker, and modern web development. Passionate about sharing knowledge and helping developers grow.

Ready to Build Something Amazing?

Let's discuss your project and explore how my expertise can help you achieve your goals. Free consultation available.

💼 Trusted by 50+ companies worldwide | ⚡ Average response time: 24 hours