.NET Aspire is a cloud-ready stack for building observable, production-ready distributed applications. Wolfix.Server uses Aspire to orchestrate the API, databases, and external services during local development.
What is .NET Aspire?
.NET Aspire provides:
Service orchestration - Start multiple services with dependencies
Service discovery - Automatic service URL resolution
Telemetry - Built-in logging, metrics, and tracing
Dashboard - Unified view of all services
Health checks - Monitor service health
Think of Aspire as “docker-compose for .NET” with built-in observability and service defaults.
Aspire Projects
Wolfix.Server includes two Aspire-related projects:
Wolfix.AppHost
The orchestrator that defines and starts all services:
Wolfix.AppHost/AppHost.cs
using DotNetEnv ;
using Wolfix . AppHost . Extensions ;
// Load environment variables
LoadOptions options = new ( onlyExactPath : true );
var envKeyValues = EnvExtensions . LoadOrThrow ( options );
var builder = DistributedApplication . CreateBuilder ( args );
// Add container dependencies
var toxicApi = builder . AddContainer ( "toxic-api" , "iluhahr/toxic-ai-api:latest" )
. WithHttpEndpoint ( targetPort : 8000 );
var mongoDb = builder . AddContainer ( "mongodb-local" , "mongo" , "latest" )
. WithEndpoint ( targetPort : 27017 , port : 27017 , name : "mongodb" , scheme : "tcp" );
// Add the API with dependencies
builder . AddProject < Projects . Wolfix_API >( "api" )
. WithEnvironment ( "TOXIC_API_BASE_URL" , toxicApi . GetEndpoint ( "http" ))
. WithCustomEnvironmentVariables ( envKeyValues )
. WaitFor ( toxicApi )
. WaitFor ( mongoDb );
builder . Build (). Run ();
Wolfix.ServiceDefaults
Shared configuration for resilience, telemetry, and health checks :
Wolfix.ServiceDefaults/Extensions.cs
public static IHostApplicationBuilder AddServiceDefaults (
this IHostApplicationBuilder builder )
{
builder . ConfigureOpenTelemetry ();
builder . AddDefaultHealthChecks ();
builder . Services . AddServiceDiscovery ();
builder . Services . ConfigureHttpClientDefaults ( http =>
{
http . AddStandardResilienceHandler ();
http . AddServiceDiscovery ();
});
return builder ;
}
Running with Aspire
Start the AppHost
cd Wolfix.AppHost
dotnet run
This will:
Pull and start Docker containers (MongoDB, Toxic API)
Start the Wolfix.API project
Launch the Aspire dashboard
Connect all services
Access the Dashboard
Once running, navigate to the dashboard URL shown in terminal output:
Aspire Dashboard: http://localhost:15000
The dashboard provides:
Resources View all services and their status
Console Logs Real-time logs from all services
Structured Logs Queryable structured logging
Traces Distributed tracing across services
Metrics Performance metrics and counters
Environment View environment variables
Aspire Configuration
Adding Containers
Add external services as containers:
// Add Redis
var redis = builder . AddRedis ( "cache" )
. WithRedisCommander (); // Adds Redis Commander UI
// Add RabbitMQ
var rabbitmq = builder . AddRabbitMQ ( "messaging" )
. WithManagementPlugin ();
// Add SQL Server
var sqlserver = builder . AddSqlServer ( "sql" )
. AddDatabase ( "wolfix" );
// Add custom container
var customService = builder . AddContainer ( "custom" , "myimage:latest" )
. WithHttpEndpoint ( targetPort : 8080 , port : 9000 )
. WithEnvironment ( "SETTING" , "value" );
Environment Variables
Pass environment variables to services:
builder . AddProject < Projects . Wolfix_API >( "api" )
. WithEnvironment ( "ASPNETCORE_ENVIRONMENT" , "Development" )
. WithEnvironment ( "DB" , "Host=localhost;Port=5432;Database=wolfix" )
. WithEnvironment ( "STRIPE_KEY" , builder . Configuration [ "STRIPE_KEY" ] ! );
Service Dependencies
Define startup order with WaitFor:
var postgres = builder . AddPostgres ( "db" );
var redis = builder . AddRedis ( "cache" );
builder . AddProject < Projects . Wolfix_API >( "api" )
. WaitFor ( postgres ) // Start postgres first
. WaitFor ( redis ); // Then redis
Loading from .env File
Wolfix.Server loads environment variables from .env:
Wolfix.AppHost/Extensions/EnvExtensions.cs
public static Dictionary < string , string > LoadOrThrow ( LoadOptions options )
{
// Load .env file
Env . Load ( options );
// Convert to dictionary
var envVars = new Dictionary < string , string >();
foreach ( DictionaryEntry entry in Environment . GetEnvironmentVariables ())
{
envVars [ entry . Key ! . ToString () ! ] = entry . Value ! . ToString () ! ;
}
return envVars ;
}
Usage:
LoadOptions options = new ( onlyExactPath : true );
var envKeyValues = EnvExtensions . LoadOrThrow ( options );
builder . AddProject < Projects . Wolfix_API >( "api" )
. WithCustomEnvironmentVariables ( envKeyValues );
Service Defaults
The Wolfix.ServiceDefaults project configures common concerns:
Open Telemetry
Automatic instrumentation for logging, metrics, and tracing:
private static IHostApplicationBuilder ConfigureOpenTelemetry (
this IHostApplicationBuilder builder )
{
builder . Logging . AddOpenTelemetry ( logging =>
{
logging . IncludeFormattedMessage = true ;
logging . IncludeScopes = true ;
});
builder . Services . AddOpenTelemetry ()
. WithMetrics ( metrics =>
{
metrics . AddAspNetCoreInstrumentation ()
. AddHttpClientInstrumentation ()
. AddRuntimeInstrumentation ();
})
. WithTracing ( tracing =>
{
tracing . AddAspNetCoreInstrumentation ()
. AddHttpClientInstrumentation ()
. AddEntityFrameworkCoreInstrumentation ();
});
builder . AddOpenTelemetryExporters ();
return builder ;
}
Health Checks
Endpoints for monitoring service health:
private static IHostApplicationBuilder AddDefaultHealthChecks (
this IHostApplicationBuilder builder )
{
builder . Services . AddHealthChecks ()
. AddCheck ( "self" , () => HealthCheckResult . Healthy (), [ "live" ]);
return builder ;
}
Access health checks:
/health - Overall health
/health/live - Liveness probe
/health/ready - Readiness probe
HTTP Resilience
Automatic retries, timeouts, and circuit breakers:
builder . Services . ConfigureHttpClientDefaults ( http =>
{
http . AddStandardResilienceHandler ();
http . AddServiceDiscovery ();
});
This adds:
Retry policy - 3 retries with exponential backoff
Circuit breaker - Opens after 5 consecutive failures
Timeout - 30 second request timeout
Using Aspire in the API
The API project references ServiceDefaults:
using Wolfix . ServiceDefaults ;
WebApplicationBuilder builder = WebApplication . CreateBuilder ( args );
// Add service defaults (telemetry, health checks, resilience)
builder . AddServiceDefaults ();
// Rest of configuration...
WebApplication app = builder . Build ();
// Map default endpoints (/health, /alive, /metrics)
app . MapDefaultEndpoints ();
// Rest of middleware...
app . Run ();
Debugging with Aspire
Debug the API
Set breakpoints in Wolfix.API
Run Wolfix.AppHost in debug mode
Aspire starts all dependencies
Debugger attaches to API
Debug AppHost
Set breakpoints in AppHost.cs
Run Wolfix.AppHost in debug mode
Step through service orchestration
View Logs in Dashboard
Open Aspire dashboard
Navigate to “Console Logs”
Select service (api, mongodb-local, toxic-api)
View real-time logs
View Traces
Open Aspire dashboard
Navigate to “Traces”
Select a trace to see:
HTTP requests
Database queries
External API calls
Timing information
Advanced Configuration
Custom Ports
builder . AddProject < Projects . Wolfix_API >( "api" )
. WithHttpEndpoint ( port : 5000 , targetPort : 8080 , name : "http" )
. WithHttpsEndpoint ( port : 5001 , targetPort : 8081 , name : "https" );
Volume Mounts
var mongo = builder . AddContainer ( "mongodb" , "mongo" , "latest" )
. WithEndpoint ( targetPort : 27017 , port : 27017 )
. WithBindMount ( "./data/mongo" , "/data/db" ); // Persist data
Multiple Instances
// Start multiple API instances
for ( int i = 0 ; i < 3 ; i ++ )
{
builder . AddProject < Projects . Wolfix_API >( $"api- { i } " )
. WithHttpEndpoint ( port : 5000 + i )
. WithReplicas ( 1 );
}
Custom Resource
public class CustomResource : ContainerResource
{
public CustomResource ( string name ) : base ( name )
{
}
}
public static class CustomResourceExtensions
{
public static IResourceBuilder < CustomResource > AddCustomService (
this IDistributedApplicationBuilder builder ,
string name )
{
var resource = new CustomResource ( name );
return builder . AddResource ( resource )
. WithImage ( "custom-image" )
. WithHttpEndpoint ( targetPort : 8080 );
}
}
// Usage
builder . AddCustomService ( "my-service" );
Aspire vs Docker Compose
Feature Aspire Docker Compose Language C# YAML Type safety ✅ Yes ❌ No Service discovery ✅ Built-in ❌ Manual Telemetry ✅ Automatic ❌ Manual setup Dashboard ✅ Built-in ❌ External tools Hot reload ✅ Yes ❌ No .NET integration ✅ Native ❌ Limited Production ready ❌ Development ✅ Yes
Aspire is designed for local development. For production, use Docker Compose, Kubernetes, or Azure Container Apps.
Production Deployment
Aspire can generate deployment manifests:
Generate Kubernetes Manifest
cd Wolfix.AppHost
dotnet run --publisher manifest --output-path ../deploy
This generates:
apiVersion : apps/v1
kind : Deployment
metadata :
name : api
spec :
replicas : 1
template :
spec :
containers :
- name : api
image : wolfix-api:latest
ports :
- containerPort : 8080
Generate Docker Compose
dotnet run --publisher compose --output-path ../deploy
Generates docker-compose.yml for production deployment.
Troubleshooting
Port Already in Use
// Change default port
builder . AddProject < Projects . Wolfix_API >( "api" )
. WithHttpEndpoint ( port : 6000 ); // Use different port
Container Failed to Start
Check Docker is running:
View container logs in Aspire dashboard.
Environment Variables Not Loaded
Ensure .env file exists in AppHost directory:
ls -la Wolfix.AppHost/.env
Dashboard Not Accessible
Check firewall settings and ensure port 15000 is open:
Next Steps
Development Guide Start building with Aspire
Deployment Deploy to production