Aspire服务默认配置Skill aspire-service-defaults

Aspire服务默认配置技能是一个用于.NET Aspire分布式应用程序开发的共享配置框架。它集中管理OpenTelemetry观测性(日志、追踪、指标)、健康检查(就绪性/存活性)、HTTP客户端弹性(重试/熔断器)和服务发现配置,确保微服务架构中的一致性和可观测性。关键词:Aspire .NET 微服务 OpenTelemetry 健康检查 服务发现 分布式系统 云原生 可观测性 DevOps

后端开发 0 次安装 0 次浏览 更新于 2/26/2026

name: aspire-service-defaults description: 为Aspire应用程序创建共享的ServiceDefaults项目。集中所有服务的OpenTelemetry、健康检查、弹性和服务发现配置。 invocable: false

Aspire 服务默认配置

何时使用此技能

在以下情况下使用此技能:

  • 构建基于Aspire的分布式应用程序
  • 需要在服务间保持一致的观测性(日志、追踪、指标)
  • 希望共享健康检查配置
  • 配置HttpClient弹性和服务发现

什么是ServiceDefaults?

ServiceDefaults是一个共享项目,为Aspire应用程序中的所有服务提供通用配置:

  • OpenTelemetry - 日志、追踪和指标
  • 健康检查 - 就绪性和存活性端点
  • 服务发现 - 自动服务解析
  • HTTP弹性 - 重试和熔断器策略

每个服务都引用此项目并调用AddServiceDefaults()


项目结构

src/
  MyApp.ServiceDefaults/
    Extensions.cs
    MyApp.ServiceDefaults.csproj
  MyApp.Api/
    Program.cs  # 调用 AddServiceDefaults()
  MyApp.Worker/
    Program.cs  # 调用 AddServiceDefaults()
  MyApp.AppHost/
    Program.cs

ServiceDefaults 项目

项目文件

<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>
    /// 添加通用的Aspire服务:OpenTelemetry、健康检查、
    /// 服务发现和HTTP弹性。
    /// </summary>
    public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder)
        where TBuilder : IHostApplicationBuilder
    {
        builder.ConfigureOpenTelemetry();
        builder.AddDefaultHealthChecks();

        builder.Services.AddServiceDiscovery();

        builder.Services.ConfigureHttpClientDefaults(http =>
        {
            // 弹性:重试、熔断器、超时
            http.AddStandardResilienceHandler();

            // 服务发现:将服务名称解析为地址
            http.AddServiceDiscovery();
        });

        return builder;
    }

    public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder)
        where TBuilder : IHostApplicationBuilder
    {
        // 日志
        builder.Logging.AddOpenTelemetry(logging =>
        {
            logging.IncludeFormattedMessage = true;
            logging.IncludeScopes = true;
        });

        builder.Services.AddOpenTelemetry()
            // 指标
            .WithMetrics(metrics =>
            {
                metrics
                    .AddAspNetCoreInstrumentation()
                    .AddHttpClientInstrumentation()
                    .AddRuntimeInstrumentation();
            })
            // 追踪
            .WithTracing(tracing =>
            {
                tracing
                    .AddSource(builder.Environment.ApplicationName)
                    .AddAspNetCoreInstrumentation(options =>
                        // 从追踪中排除健康检查
                        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
    {
        // 如果配置了端点(Aspire仪表板、Jaeger等),则使用OTLP导出器
        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>
    /// 映射健康检查端点。在UseRouting()之后调用。
    /// </summary>
    public static WebApplication MapDefaultEndpoints(this WebApplication app)
    {
        // 仅在开发环境中暴露 - 参见下面的安全说明
        if (app.Environment.IsDevelopment())
        {
            // 就绪性:所有健康检查必须通过
            app.MapHealthChecks(HealthEndpointPath);

            // 存活性:仅包含标记为“live”的检查
            app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions
            {
                Predicate = r => r.Tags.Contains("live")
            });
        }

        return app;
    }
}

在服务中的使用

API 服务

var builder = WebApplication.CreateBuilder(args);

// 添加所有服务默认配置
builder.AddServiceDefaults();

// 添加您的服务
builder.Services.AddControllers();

var app = builder.Build();

// 映射健康端点
app.MapDefaultEndpoints();

app.MapControllers();
app.Run();

Worker 服务

var builder = Host.CreateApplicationBuilder(args);

// 也适用于非Web主机
builder.AddServiceDefaults();

builder.Services.AddHostedService<MyWorker>();

var host = builder.Build();
host.Run();

添加自定义健康检查

public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder builder)
    where TBuilder : IHostApplicationBuilder
{
    builder.Services.AddHealthChecks()
        // 基本存活性
        .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"])

        // 数据库就绪性
        .AddNpgSql(
            builder.Configuration.GetConnectionString("postgres")!,
            name: "postgres",
            tags: ["ready"])

        // Redis就绪性
        .AddRedis(
            builder.Configuration.GetConnectionString("redis")!,
            name: "redis",
            tags: ["ready"])

        // 自定义检查
        .AddCheck<MyCustomHealthCheck>("custom", tags: ["ready"]);

    return builder;
}

添加自定义追踪源

对于Akka.NET或自定义ActivitySources:

public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder)
    where TBuilder : IHostApplicationBuilder
{
    builder.Services.AddOpenTelemetry()
        .WithTracing(tracing =>
        {
            tracing
                .AddSource(builder.Environment.ApplicationName)
                // Akka.NET追踪
                .AddSource("Akka.NET")
                // 自定义源
                .AddSource("MyApp.Orders")
                .AddSource("MyApp.Payments")
                .AddAspNetCoreInstrumentation()
                .AddHttpClientInstrumentation();
        });

    return builder;
}

生产环境健康检查

对于生产环境,保护健康端点或使用不同的路径:

public static WebApplication MapDefaultEndpoints(this WebApplication app)
{
    // 始终为Kubernetes探针映射,但请考虑:
    // - 使用仅内部端口
    // - 添加授权
    // - 速率限制

    app.MapHealthChecks("/health", new HealthCheckOptions
    {
        // 仅返回状态,不返回详细信息
        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;
}

与AppHost集成

AppHost自动配置OTLP端点:

// 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();

服务自动接收OTEL_EXPORTER_OTLP_ENDPOINT,将遥测数据发送到Aspire仪表板。


最佳实践

实践 原因
一个ServiceDefaults项目 所有服务配置一致
从追踪中过滤健康检查 减少观测性数据中的噪音
标记健康检查 将存活性与就绪性分离
使用StandardResilienceHandler 内置重试、熔断器、超时
添加自定义追踪源 捕获特定领域的跨度

资源