--- name: aspire description: > .NET Aspire for cloud-native orchestration. Covers AppHost configuration, service defaults, resource configuration, service discovery, and the Aspire dashboard. Load this skill when setting up local development orchestration, service discovery, or Aspire-managed infrastructure, or when the user mentions "Aspire", "AppHost", "service defaults", "service discovery", "orchestration", "Aspire dashboard", "AddProject", "WithReference", or "cloud-native .NET". --- # .NET Aspire ## Core Principles 1. **AppHost orchestrates; it is never deployed itself** — Aspire's core job is the local development experience: starting services, databases, and message brokers together. Modern Aspire also generates deployment assets (`aspire publish` for docker-compose/Kubernetes manifests, `aspire deploy` for Azure Container Apps) — but the AppHost process itself stays a dev/build-time tool, not a production runtime. 2. **Service defaults are your baseline** — The `ServiceDefaults` project configures OpenTelemetry, health checks, and resilience for all services in one place. 3. **Use Aspire integrations** — Aspire has built-in integrations for PostgreSQL, Redis, RabbitMQ, SQL Server, and more. They handle connection strings, health checks, and tracing automatically. 4. **The dashboard is your observability tool** — Use the Aspire dashboard for local development tracing, logging, and metrics instead of setting up Seq/Grafana locally. ## Patterns ### AppHost Configuration ```csharp // AppHost/Program.cs var builder = DistributedApplication.CreateBuilder(args); // Infrastructure resources var postgres = builder.AddPostgres("postgres") .WithPgAdmin() .AddDatabase("myappdb"); var redis = builder.AddRedis("redis") .WithRedisInsight(); var rabbitmq = builder.AddRabbitMQ("messaging") .WithManagementPlugin(); // Application projects var api = builder.AddProject("api") .WithReference(postgres) .WithReference(redis) .WithReference(rabbitmq) .WithExternalHttpEndpoints(); var worker = builder.AddProject("worker") .WithReference(postgres) .WithReference(rabbitmq); builder.Build().Run(); ``` ### Service Defaults ```csharp // ServiceDefaults/Extensions.cs — Standard Aspire service defaults // Configures OpenTelemetry (metrics + tracing), health checks, service discovery, and resilience public static class Extensions { public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) { builder.ConfigureOpenTelemetry(); builder.AddDefaultHealthChecks(); builder.Services.AddServiceDiscovery(); builder.Services.ConfigureHttpClientDefaults(http => { http.AddStandardResilienceHandler(); http.AddServiceDiscovery(); }); return builder; } // ConfigureOpenTelemetry: adds logging, metrics (ASP.NET, HttpClient, Runtime), // tracing (ASP.NET, HttpClient, EF Core), and OTLP exporter if configured // AddDefaultHealthChecks: adds a "self" liveness check tagged ["live"] } ``` ### Using Service Defaults in a Project ```csharp // MyApp.Api/Program.cs var builder = WebApplication.CreateBuilder(args); builder.AddServiceDefaults(); // Add Aspire integrations builder.AddNpgsqlDbContext("myappdb"); builder.AddRedisDistributedCache("redis"); var app = builder.Build(); app.MapDefaultEndpoints(); // health check endpoints app.Run(); ``` ### Service-to-Service Communication ```csharp // AppHost — configure service references var orderApi = builder.AddProject("order-api"); var paymentApi = builder.AddProject("payment-api") .WithReference(orderApi); // paymentApi can discover orderApi // In PaymentApi — use service discovery builder.Services.AddHttpClient(client => { client.BaseAddress = new Uri("https+http://order-api"); }); ``` ### Solution Structure with Aspire ``` MyApp.slnx ├── MyApp.AppHost/ # Aspire orchestrator │ └── Program.cs ├── MyApp.ServiceDefaults/ # Shared service configuration │ └── Extensions.cs ├── src/ │ ├── MyApp.Api/ # Web API project │ └── MyApp.Worker/ # Background worker └── tests/ └── MyApp.Api.Tests/ ``` ## Anti-patterns ### Don't Deploy the AppHost Process ```csharp // BAD — running the AppHost executable in production as an orchestrator // The AppHost is a dev/build-time tool, not a production runtime // GOOD — deploy the generated assets, not the AppHost: // aspire publish → docker-compose / Kubernetes manifests from the app model // aspire deploy → direct deployment (e.g., Azure Container Apps) ``` ### Don't Hardcode Connection Strings with Aspire ```csharp // BAD — hardcoding connection strings defeats Aspire's purpose builder.Services.AddDbContext(o => o.UseNpgsql("Host=localhost;Database=myapp;...")); // GOOD — use Aspire integration (connection string injected automatically) builder.AddNpgsqlDbContext("myappdb"); ``` ### Don't Skip Service Defaults ```csharp // BAD — manually configuring each service builder.Services.AddOpenTelemetry()... builder.Services.AddHealthChecks()... // GOOD — use shared service defaults builder.AddServiceDefaults(); ``` ## Decision Guide | Scenario | Recommendation | |----------|---------------| | Local dev with multiple services | Aspire AppHost | | Single-project local dev | `dotnet run` is fine, Aspire optional | | Shared service configuration | ServiceDefaults project | | Database for local dev | Aspire `AddPostgres()` / `AddSqlServer()` | | Service discovery | Aspire's built-in service discovery | | Production deployment | `aspire publish` (compose/K8s manifests) or `aspire deploy` (ACA); never the AppHost itself | | Observability in local dev | Aspire dashboard (auto-configured) |