
Aspire Service Defaults
- 361 installs
- 1.1k repo stars
- Updated July 3, 2026
- aaronontheweb/dotnet-skills
aspire-service-defaults is an agent skill that creates a shared Aspire ServiceDefaults project with OpenTelemetry, health checks, resilience, and service discovery for developers building production-ready .NET microservi
About
aspire-service-defaults is an agent skill from aaronontheweb/dotnet-skills for .NET Aspire distributed applications. The skill creates a shared ServiceDefaults project that centralizes OpenTelemetry logging, tracing, and metrics, health check configuration, HttpClient resilience policies, and service discovery across every microservice in an Aspire app host solution. It gives each service consistent observability and production baselines instead of duplicating boilerplate Program.cs configuration. Developers reach for aspire-service-defaults when bootstrapping Aspire-based microservices that need uniform telemetry, health endpoints, and resilient HTTP clients from day one.
- Standardizes OpenTelemetry wiring
- Adds health check endpoints by default
- Configures resilient HttpClient policies
- Reduces duplicated bootstrap code
Aspire Service Defaults by the numbers
- 361 all-time installs (skills.sh)
- Ranked #52 of 153 .NET & C# skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aaronontheweb/dotnet-skills --skill aspire-service-defaultsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 361 |
|---|---|
| repo stars | ★ 1.1k |
| Last updated | July 3, 2026 |
| Repository | aaronontheweb/dotnet-skills ↗ |
How do you add Aspire service defaults to .NET microservices?
Apply Aspire service defaults for telemetry, health checks, resilience, and OpenTelemetry so each .NET microservice boots with production-ready baselines.
Who is it for?
Developers bootstrapping .NET Aspire distributed apps who need consistent observability and resilience across services.
Skip if: Developers on single-monolith ASP.NET apps without Aspire orchestration or shared microservice defaults requirements.
When should I use this skill?
A developer builds an Aspire distributed app and needs shared OpenTelemetry, health checks, resilience, or service discovery defaults.
What you get
Shared ServiceDefaults project with OpenTelemetry, health checks, HttpClient resilience, and service discovery configuration.
- ServiceDefaults.csproj
- shared OpenTelemetry configuration
- health check and resilience setup
Files
Aspire Service Defaults
When to Use This Skill
Use this skill when:
- Building Aspire-based distributed applications
- Need consistent observability (logging, tracing, metrics) across services
- Want shared health check configuration
- Configuring HttpClient resilience and service discovery
---
What is ServiceDefaults?
ServiceDefaults is a shared project that provides common configuration for all services in an Aspire application:
- OpenTelemetry - Logging, tracing, and metrics
- Health Checks - Readiness and liveness endpoints
- Service Discovery - Automatic service resolution
- HTTP Resilience - Retry and circuit breaker policies
Every service references this project and calls AddServiceDefaults().
---
Project Structure
src/
MyApp.ServiceDefaults/
Extensions.cs
MyApp.ServiceDefaults.csproj
MyApp.Api/
Program.cs # Calls AddServiceDefaults()
MyApp.Worker/
Program.cs # Calls AddServiceDefaults()
MyApp.AppHost/
Program.cs---
ServiceDefaults Project
Project File
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<IsAspireSharedProject>true</IsAspireSharedProject>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
</ItemGroup>
</Project>Extensions.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
namespace Microsoft.Extensions.Hosting;
public static class Extensions
{
private const string HealthEndpointPath = "/health";
private const string AlivenessEndpointPath = "/alive";
/// <summary>
/// Adds common Aspire services: OpenTelemetry, health checks,
/// service discovery, and HTTP resilience.
/// </summary>
public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder)
where TBuilder : IHostApplicationBuilder
{
builder.ConfigureOpenTelemetry();
builder.AddDefaultHealthChecks();
builder.Services.AddServiceDiscovery();
builder.Services.ConfigureHttpClientDefaults(http =>
{
// Resilience: retries, circuit breaker, timeouts
http.AddStandardResilienceHandler();
// Service discovery: resolve service names to addresses
http.AddServiceDiscovery();
});
return builder;
}
public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder)
where TBuilder : IHostApplicationBuilder
{
// Logging
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
});
builder.Services.AddOpenTelemetry()
// Metrics
.WithMetrics(metrics =>
{
metrics
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation();
})
// Tracing
.WithTracing(tracing =>
{
tracing
.AddSource(builder.Environment.ApplicationName)
.AddAspNetCoreInstrumentation(options =>
// Exclude health checks from traces
options.Filter = context =>
!context.Request.Path.StartsWithSegments(HealthEndpointPath) &&
!context.Request.Path.StartsWithSegments(AlivenessEndpointPath))
.AddHttpClientInstrumentation();
});
builder.AddOpenTelemetryExporters();
return builder;
}
private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuilder builder)
where TBuilder : IHostApplicationBuilder
{
// Use OTLP exporter if endpoint is configured (Aspire Dashboard, Jaeger, etc.)
var useOtlp = !string.IsNullOrWhiteSpace(
builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
if (useOtlp)
{
builder.Services.AddOpenTelemetry().UseOtlpExporter();
}
return builder;
}
public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder builder)
where TBuilder : IHostApplicationBuilder
{
builder.Services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
return builder;
}
/// <summary>
/// Maps health check endpoints. Call after UseRouting().
/// </summary>
public static WebApplication MapDefaultEndpoints(this WebApplication app)
{
// Only expose in development - see security note below
if (app.Environment.IsDevelopment())
{
// Readiness: all health checks must pass
app.MapHealthChecks(HealthEndpointPath);
// Liveness: only "live" tagged checks
app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("live")
});
}
return app;
}
}---
Usage in Services
API Service
var builder = WebApplication.CreateBuilder(args);
// Add all service defaults
builder.AddServiceDefaults();
// Add your services
builder.Services.AddControllers();
var app = builder.Build();
// Map health endpoints
app.MapDefaultEndpoints();
app.MapControllers();
app.Run();Worker Service
var builder = Host.CreateApplicationBuilder(args);
// Works for non-web hosts too
builder.AddServiceDefaults();
builder.Services.AddHostedService<MyWorker>();
var host = builder.Build();
host.Run();---
Adding Custom Health Checks
public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder builder)
where TBuilder : IHostApplicationBuilder
{
builder.Services.AddHealthChecks()
// Basic liveness
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"])
// Database readiness
.AddNpgSql(
builder.Configuration.GetConnectionString("postgres")!,
name: "postgres",
tags: ["ready"])
// Redis readiness
.AddRedis(
builder.Configuration.GetConnectionString("redis")!,
name: "redis",
tags: ["ready"])
// Custom check
.AddCheck<MyCustomHealthCheck>("custom", tags: ["ready"]);
return builder;
}---
Adding Custom Trace Sources
For Akka.NET or custom ActivitySources:
public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder)
where TBuilder : IHostApplicationBuilder
{
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing
.AddSource(builder.Environment.ApplicationName)
// Akka.NET tracing
.AddSource("Akka.NET")
// Custom sources
.AddSource("MyApp.Orders")
.AddSource("MyApp.Payments")
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation();
});
return builder;
}---
Production Health Checks
For production, protect health endpoints or use different paths:
public static WebApplication MapDefaultEndpoints(this WebApplication app)
{
// Always map for Kubernetes probes, but consider:
// - Using internal-only ports
// - Adding authorization
// - Rate limiting
app.MapHealthChecks("/health", new HealthCheckOptions
{
// Only return status, not details
ResponseWriter = (context, report) =>
{
context.Response.ContentType = "text/plain";
return context.Response.WriteAsync(report.Status.ToString());
}
});
app.MapHealthChecks("/alive", new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("live"),
ResponseWriter = (context, report) =>
{
context.Response.ContentType = "text/plain";
return context.Response.WriteAsync(report.Status.ToString());
}
});
return app;
}---
Integration with AppHost
The AppHost automatically configures OTLP endpoints:
// AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddPostgres("postgres");
var redis = builder.AddRedis("redis");
var api = builder.AddProject<Projects.MyApp_Api>("api")
.WithReference(postgres)
.WithReference(redis);
builder.Build().Run();Services receive OTEL_EXPORTER_OTLP_ENDPOINT automatically, sending telemetry to the Aspire Dashboard.
---
Best Practices
| Practice | Reason |
|---|---|
| One ServiceDefaults project | Consistent config across all services |
| Filter health checks from traces | Reduces noise in observability data |
| Tag health checks | Separate liveness from readiness |
| Use StandardResilienceHandler | Built-in retry, circuit breaker, timeout |
| Add custom trace sources | Capture domain-specific spans |
---
Resources
- Aspire Service Defaults: https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/service-defaults
- OpenTelemetry .NET: https://opentelemetry.io/docs/languages/net/
- Health Checks: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks
Related skills
How it compares
Use aspire-service-defaults for Aspire shared baselines instead of hand-copying OpenTelemetry setup into each service.
FAQ
What does Aspire ServiceDefaults include?
Aspire ServiceDefaults includes shared OpenTelemetry logging, tracing, and metrics, health check configuration, HttpClient resilience policies, and service discovery setup. aspire-service-defaults scaffolds that shared project for every service in an Aspire solution.
When should developers use aspire-service-defaults?
Developers should use aspire-service-defaults when building Aspire-based distributed applications that need consistent observability and resilience across services. The skill avoids duplicating telemetry and health check boilerplate in each microservice.