Aspire Service Defaults

aaronontheweb/dotnet-skills/skills/aspire-service-defaults

作者 aarononthewebe426ed93a9f3無授權條款1.2K 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫3 週前更新

Create a shared ServiceDefaults project for Aspire applications. Centralizes OpenTelemetry, health checks, resilience, and service discovery configuration across all services.

AI 產生的概覽

建立共用的 Aspire ServiceDefaults 專案,集中管理 OpenTelemetry、健康檢查、復原力和服務探索。

功能
提供在 .NET Aspire 分散式應用程式中建置共用 ServiceDefaults 專案的說明和 C# 程式碼。內容涵蓋專案檔、包含 AddServiceDefaults 的 Extensions.cs、OpenTelemetry 設定、健康檢查端點、HTTP 復原力和服務探索。也展示 API 與背景服務如何呼叫這些擴充方法,以及如何新增自訂健康檢查和追蹤來源。
適用情境
適用於建置需要跨服務保持一致可觀測性、健康檢查、復原力和服務探索的 Aspire 分散式應用程式。也適用於設定 HttpClient 復原力或共用健康檢查端點。
執行需求
需要 .NET 9 Aspire 應用程式以及所引用的 NuGet 套件(OpenTelemetry、Microsoft.Extensions.Http.Resilience、Microsoft.Extensions.ServiceDiscovery)。不包含指令碼,僅為說明和程式碼範例。

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

xml
<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

csharp
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

csharp
var builder = WebApplication.CreateBuilder(args);
// Add all service defaultsbuilder.AddServiceDefaults();
// Add your servicesbuilder.Services.AddControllers();
var app = builder.Build();
// Map health endpointsapp.MapDefaultEndpoints();
app.MapControllers();app.Run();

Worker Service

csharp
var builder = Host.CreateApplicationBuilder(args);
// Works for non-web hosts toobuilder.AddServiceDefaults();
builder.Services.AddHostedService<MyWorker>();
var host = builder.Build();host.Run();

Adding Custom Health Checks

csharp
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:

csharp
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:

csharp
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:

csharp
// AppHost/Program.csvar 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

PracticeReason
One ServiceDefaults projectConsistent config across all services
Filter health checks from tracesReduces noise in observability data
Tag health checksSeparate liveness from readiness
Use StandardResilienceHandlerBuilt-in retry, circuit breaker, timeout
Add custom trace sourcesCapture domain-specific spans

Resources

來源與署名

來源:aaronontheweb/dotnet-skills位於skills/aspire-service-defaults提交e426ed9

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架