关于 dotnet-aspire-patterns
dotnet-aspire-patterns 是面向分布式应用开发者的 .NET Aspire 技能,涵盖 AppHost 编排、服务发现、后端服务组件、本地可观测性和健康检查,并区分开发编排与生产部署。
主要功能
- 01AppHost 拓扑与资源生命周期
- 02服务发现和连接字符串
- 03数据库、缓存与消息代理组件
- 04用于健康检查和遥测的 ServiceDefaults
- 05展示日志、追踪和指标的本地仪表板
- 06Aspire 与手动编排的选型指导
适用场景
- 01连接多个 .NET 服务和后端基础设施
- 02依据资源健康状态安排启动顺序
- 03统一各服务项目的可观测性
- 04评估本地编排方案
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill dotnet-aspire-patterns安装后在 Claude Code 中输入/dotnet-aspire-patterns确认已加载。
详细介绍
dotnet-aspire-patterns
用于构建云就绪型分布式应用的 .NET Aspire 编排模式。涵盖 AppHost 配置、服务发现、用于集成后端服务(数据库、缓存、消息代理)的组件模型、本地可观测性 Aspire 仪表板、分布式运行状况检查,以及何时选择 Aspire 而非手动容器编排。
不在范围内: 编写原始 Dockerfile 和多阶段构建——请参阅 [skill:dotnet-containers]。Kubernetes 清单、Helm 图表和 Docker Compose——请参阅 [skill:dotnet-container-deployment]。OpenTelemetry SDK 配置和自定义指标——请参阅 [skill:dotnet-observability]。DI 服务生命周期机制——请参阅 [skill:dotnet-csharp-dependency-injection]。后台服务托管——请参阅 [skill:dotnet-background-services]。
交叉引用:[skill:dotnet-containers] 介绍容器镜像优化和基础镜像选择,[skill:dotnet-container-deployment] 介绍生产环境中的 Kubernetes/Compose 部署,[skill:dotnet-observability] 介绍 Aspire 默认设置以外的 OpenTelemetry 详细信息,[skill:dotnet-csharp-dependency-injection] 介绍 DI 基础知识,[skill:dotnet-background-services] 介绍托管服务生命周期模式。
Aspire 概述
.NET Aspire 是一个有主见的技术栈,用于构建可观测、可用于生产环境的分布式应用。它提供:
- 编排——使用 C# 定义分布式拓扑(AppHost)
- 组件——用于常见后端服务的预配置 NuGet 包
- 服务默认配置——用于 OpenTelemetry、运行状况检查和弹性的共享配置
- 仪表板——用于本地开发的 UI,可查看跟踪、日志、指标和资源状态
Aspire 不是部署目标。它负责编排本地开发和测试体验。对于生产环境,它会生成由部署工具(Azure Developer CLI、Kubernetes 等)使用的清单。
何时使用 Aspire
| 场景 | 建议 |
|---|---|
| 多个 .NET 服务 + 后端基础设施 | Aspire AppHost——简化本地开发和服务连接 |
| 单个 API 和一个数据库 | 可选——对于简单的拓扑,Aspire 会增加开销 |
| 仅使用非 .NET 服务(Node、Python) | Aspire 可以引用容器镜像,但工具带来的好处会减少 |
| 已需要 Kubernetes/Compose 用于本地开发 | 评估迁移成本;在开发场景中,Aspire 可替代 docker-compose |
| 团队需要统一的可观测性默认设置 | Aspire ServiceDefaults 可在所有项目中统一 OTel 配置 |
AppHost 配置
AppHost 是一个 .NET 项目(Aspire.Hosting.AppHost SDK),用于定义分布式应用拓扑。它引用其他项目和后端服务,并通过服务发现将它们连接起来。
AppHost 项目设置
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.1.*" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<IsAspireHost>true</IsAspireHost>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.1.*" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.1.*" />
<PackageReference Include="Aspire.Hosting.Redis" Version="9.1.*" />
<PackageReference Include="Aspire.Hosting.RabbitMQ" Version="9.1.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MyApi\MyApi.csproj" />
<ProjectReference Include="..\MyWorker\MyWorker.csproj" />
</ItemGroup>
</Project>
定义拓扑
var builder = DistributedApplication.CreateBuilder(args);
// Backing services -- Aspire manages containers automatically
var postgres = builder.AddPostgres("pg")
.WithPgAdmin() // Adds pgAdmin UI container
.AddDatabase("ordersdb");
var redis = builder.AddRedis("cache")
.WithRedisCommander(); // Adds Redis Commander UI
var rabbitmq = builder.AddRabbitMQ("messaging")
.WithManagementPlugin(); // Adds RabbitMQ management UI
// Application projects -- wired with service discovery
var api = builder.AddProject<Projects.MyApi>("api")
.WithReference(postgres)
.WithReference(redis)
.WithReference(rabbitmq)
.WithExternalHttpEndpoints(); // Marks endpoints as public in deployment manifests
builder.AddProject<Projects.MyWorker>("worker")
.WithReference(postgres)
.WithReference(rabbitmq)
.WaitFor(api); // Start worker after API is healthy
builder.Build().Run();
资源生命周期
WaitFor 控制启动顺序。资源会等到依赖项报告运行状况正常后再启动:
// Worker waits for both the database and API to be ready
builder.AddProject<Projects.MyWorker>("worker")
.WithReference(postgres)
.WaitFor(postgres) // Wait for database container health check
.WaitFor(api); // Wait for API health endpoint
如果不使用 WaitFor,资源会并行启动。仅在启动顺序重要时使用它(例如,需要数据库架构已存在的工作器)。
服务发现
Aspire 会自动配置服务发现,使项目可以通过资源名称而非硬编码 URL 相互解析。
工作原理
- AppHost 将终结点信息作为环境变量和配置注入
Aspire.ServiceDefaults项目配置Microsoft.Extensions.ServiceDiscovery- 应用代码通过
HttpClient或连接字符串按名称解析服务
使用已发现的服务
// In MyApi/Program.cs
var builder = WebApplication.CreateBuilder(args);
// AddServiceDefaults registers service discovery, OpenTelemetry, health checks
builder.AddServiceDefaults();
// HttpClient resolves "worker" via service discovery
builder.Services.AddHttpClient("worker-client", client =>
{
client.BaseAddress = new Uri("https+http://worker");
});
https+http:// 方案前缀会告知服务发现提供程序优先尝试 HTTPS,失败时回退到 HTTP。这是在 Aspire 中进行服务间通信的推荐模式。
连接字符串
对于后端服务(数据库、缓存),Aspire 会通过标准的 ConnectionStrings 配置节注入连接字符串:
// AppHost: .WithReference(postgres) on the API project
// injects ConnectionStrings__ordersdb automatically
// In MyApi/Program.cs
builder.AddNpgsqlDbContext<OrdersDbContext>("ordersdb");
// Resolves ConnectionStrings:ordersdb from configuration
组件模型
Aspire 组件是 NuGet 包,可为后端服务提供预配置的客户端集成。它们负责连接管理、运行状况检查、遥测和弹性。
Hosting 包与客户端包
| 包类型 | 安装位置 | 用途 |
|---|---|---|
Aspire.Hosting.* | AppHost 项目 | 定义和配置资源(容器、连接) |
Aspire.* (client) | 服务项目 | 使用资源并启用运行状况检查和遥测 |
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.1.*" />
<PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.1.*" />
常见组件
| 组件 | Hosting 包 | 客户端包 |
|---|---|---|
| PostgreSQL(EF Core) | Aspire.Hosting.PostgreSQL | Aspire.Npgsql.EntityFrameworkCore.PostgreSQL |
| PostgreSQL(Npgsql) | Aspire.Hosting.PostgreSQL | Aspire.Npgsql |
| Redis(缓存) | Aspire.Hosting.Redis | Aspire.StackExchange.Redis |
| Redis(输出缓存) | Aspire.Hosting.Redis | Aspire.StackExchange.Redis.OutputCaching |
| RabbitMQ | Aspire.Hosting.RabbitMQ | Aspire.RabbitMQ.Client |
| Azure Service Bus | Aspire.Hosting.Azure.ServiceBus | Aspire.Azure.Messaging.ServiceBus |
| SQL Server(EF Core) | Aspire.Hosting.SqlServer | Aspire.Microsoft.EntityFrameworkCore.SqlServer |
| MongoDB | Aspire.Hosting.MongoDB | Aspire.MongoDB.Driver |
客户端注册
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// Each Add* method registers the client, health check, and telemetry
builder.AddNpgsqlDbContext<OrdersDbContext>("ordersdb");
builder.AddRedisClient("cache");
builder.AddRabbitMQClient("messaging");
组件的 Add* 方法:
- 在 DI 中注册客户端/DbContext
- 为资源添加运行状况检查
- 为客户端配置 OpenTelemetry 检测
- 应用默认弹性设置(重试、超时)
ServiceDefaults
ServiceDefaults 项目是一个由所有服务项目引用的共享库。它统一处理横切关注点。
ServiceDefaults 的配置内容
public static class Extensions
{
public static IHostApplicationBuilder AddServiceDefaults(
this IHostApplicationBuilder builder)
{
// Service discovery
builder.ConfigureOpenTelemetry();
builder.AddDefaultHealthChecks();
builder.Services.AddServiceDiscovery();
// Resilience for HttpClient
builder.Services.ConfigureHttpClientDefaults(http =>
{
http.AddStandardResilienceHandler();
http.AddServiceDiscovery();
});
return builder;
}
public 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()
.AddGrpcClientInstrumentation()
.AddHttpClientInstrumentation());
builder.AddOpenTelemetryExporters();
return builder;
}
public static IHostApplicationBuilder AddDefaultHealthChecks(
this IHostApplicationBuilder builder)
{
builder.Services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy());
return builder;
}
public static WebApplication MapDefaultEndpoints(
this WebApplication app)
{
app.MapHealthChecks("/health");
app.MapHealthChecks("/alive", new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("live")
});
return app;
}
}
使用 ServiceDefaults
每个服务项目都会引用 ServiceDefaults 项目并调用扩展方法:
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// ... service-specific registrations
var app = builder.Build();
app.MapDefaultEndpoints();
// ... middleware and endpoints
app.Run();
控制面板
Aspire 控制面板提供本地可观测性 UI,会随 AppHost 自动启动。它会显示:
- 资源 —— 所有项目、容器和可执行文件的状态
- 控制台日志 —— 汇总所有资源的 stdout/stderr
- 结构化日志 —— 带结构化属性的 OpenTelemetry 日志记录
- 追踪 —— 所有服务间的分布式追踪
- 指标 —— 实时指标图表
访问控制面板
运行 AppHost(dotnet run --project MyApp.AppHost)时,控制面板 URL 会打印到控制台:
info: Aspire.Hosting.DistributedApplication[0]
Login to the dashboard at https://localhost:17043/login?t=<token>
在非 Aspire 项目中使用控制面板
对于未使用完整 Aspire 技术栈的项目,控制面板可作为独立容器使用:
docker run --rm -it -p 18888:18888 -p 4317:18889 \
-d --name aspire-dashboard \
mcr.microsoft.com/dotnet/aspire-dashboard:9.1
将应用配置为向 http://localhost:4317 导出 OTLP 遥测数据,然后通过 http://localhost:18888 查看。
运行状况检查和分布式追踪
组件运行状况检查
每个 Aspire 组件都会自动注册运行状况检查。AppHost 会用这些检查来确定资源是否就绪:
// In AppHost -- WaitFor uses health checks to gate startup
builder.AddProject<Projects.MyApi>("api")
.WithReference(postgres)
.WaitFor(postgres); // Waits for Npgsql health check to pass
自定义运行状况检查
在 Aspire 默认检查之外,添加特定于应用的运行状况检查:
builder.Services.AddHealthChecks()
.AddCheck<OrderProcessingHealthCheck>(
"order-processing",
tags: ["ready"]);
有关运行状况检查模式(存活性与就绪性、自定义检查、运行状况检查发布)的详细信息,请参阅 [skill:dotnet-observability]。
分布式追踪集成
Aspire 通过 ServiceDefaults 配置 OpenTelemetry 追踪。追踪会自动跨 HTTP 边界传播。如需自定义 Span:
private static readonly ActivitySource s_activitySource = new("MyApp.Orders");
public async Task<Order> ProcessOrderAsync(CreateOrderRequest request, CancellationToken ct)
{
using var activity = s_activitySource.StartActivity("ProcessOrder");
activity?.SetTag("order.customer_id", request.CustomerId);
// Calls to other Aspire services carry trace context automatically
var inventory = await _httpClient.GetFromJsonAsync<InventoryResponse>(
$"https+http://inventory-api/api/stock/{request.ProductId}", ct);
// ... process order
return order;
}
有关分布式追踪的全面指南(自定义 ActivitySource、追踪上下文传播、Span 事件),请参阅 [skill:dotnet-observability]。
容器资源
添加容器镜像
对于没有 Aspire 组件的服务,可添加任意容器镜像:
var seq = builder.AddContainer("seq", "datalust/seq")
.WithHttpEndpoint(port: 5341, targetPort: 80)
.WithEnvironment("ACCEPT_EULA", "Y");
// Reference the container from a project
builder.AddProject<Projects.MyApi>("api")
.WithReference(seq);
持久卷
默认情况下,Aspire 容器使用临时存储。添加卷以便在重启后保留数据:
var postgres = builder.AddPostgres("pg")
.WithDataVolume("pg-data") // Named volume for data persistence
.AddDatabase("ordersdb");
外部资源
引用 Aspire 未管理的现有基础设施:
// Connection string from configuration (not an Aspire-managed container)
var existingDb = builder.AddConnectionString("legacydb");
builder.AddProject<Projects.MyApi>("api")
.WithReference(existingDb);
Aspire 与手动容器编排
| 关注点 | Aspire | Docker Compose / 手动方式 |
|---|---|---|
| 配置语言 | C#(强类型) | YAML |
| 服务发现 | 自动(注入环境变量) | 手动配置 DNS/环境变量 |
| 健康检查 | 每个组件自动配置 | 为每项服务手动配置 HEALTHCHECK |
| 可观测性 | 预配置 OTel + 仪表板 | 手动配置 OTel 收集器 |
| IDE 集成 | 热重载、F5 调试 | 手动附加调试器 |
| 生产部署 | 生成清单(AZD、K8s) | 直接编写清单 |
| 非 .NET 服务 | 容器引用(集成度较低) | 对所有语言一视同仁地支持 |
| 学习曲线 | .NET 专属抽象 | 行业标准工具 |
当你的技术栈主要使用 .NET,且希望获得标准化的可观测性、服务发现和简化的本地开发体验时,选择 Aspire。当你需要精细控制、多语言服务,或团队已经熟练掌握 Compose/Kubernetes 时,选择手动编排。
核心原则
- AppHost 仅用于开发阶段——它负责编排本地开发,而非生产部署
- 使用组件,而非原始连接字符串——组件会自动添加健康检查、遥测和弹性功能
- ServiceDefaults 不可或缺——每个 Aspire 服务项目都必须引用它,以确保可观测性一致
- 通过 WaitFor 控制启动顺序——将其用于实际依赖(架构迁移、种子数据),而非每项资源
- 不要重复配置 OTel——Aspire ServiceDefaults 会配置 OpenTelemetry;手动配置会导致重复收集
Agent 注意事项
- 不要在 Aspire 服务项目中手动配置 OpenTelemetry——ServiceDefaults 已注册 OTel 提供程序。添加手动
.AddOpenTelemetry()调用会导致重复收集跟踪和指标,并增加遥测成本。 - 不要在 Aspire 服务项目中硬编码连接字符串——使用
builder.AddNpgsqlDbContext<T>("name")或builder.Configuration.GetConnectionString("name")。Aspire 会通过环境变量注入连接字符串;硬编码值会绕过服务发现。 - 不要对每项资源都使用
WaitFor——这会使启动过程串行化并延长启动时间。仅当服务确实无法在没有依赖项的情况下启动时才使用(例如,启动时执行数据库迁移)。 - 不要在服务项目中引用
Aspire.Hosting.*包——Hosting 包仅应放在 AppHost 中。服务项目应使用客户端包(Aspire.Npgsql、Aspire.StackExchange.Redis等)。 - 不要将 AppHost 与生产主机混为一谈——AppHost 在本地(或 CI 中)运行,用于编排资源。生产部署使用生成的清单或基础设施即代码。
- 新服务项目中不要省略
AddServiceDefaults()——缺少它会导致项目缺失服务发现、健康检查和遥测功能,从而使 Aspire 集成在无提示的情况下失效。
先决条件
- .NET 10 SDK(或安装了 Aspire 工作负载的 .NET 8/9)
- Docker Desktop 或 Podman(用于容器资源)
- Aspire 工作负载:
dotnet workload install aspire