关于 dotnet-aspire
.NET Aspire Integration Skill 提供在现有 .NET 解决方案中加入 .NET Aspire,或创建 Aspire 分布式应用的模块化指南,涵盖服务编排、发现、配置、可观测性、资源集成和部署。
主要功能
- 01AppHost 与 ServiceDefaults 配置指南
- 02服务编排与发现模式
- 03配置及机密管理指南
- 04可观测性与本地仪表板设置
- 05资源集成与部署指南
适用场景
- 01为多服务 .NET 解决方案添加 Aspire
- 02创建启用 Aspire 的分布式应用
- 03设置本地服务编排
- 04准备云部署配置
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ markpitt/ claude-skills --skill dotnet-aspire安装后在 Claude Code 中输入/dotnet-aspire确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
resources/components.mdconfiguration-management.mddeployment.mdlocal-development.mdservice-communication.md详细介绍
.NET Aspire 集成技能
此技能可帮助你将 .NET Aspire 添加到现有的 .NET 解决方案中,或创建启用了 Aspire 的新分布式应用程序。它提供有关编排、服务发现、组件集成、配置管理和部署的模块化指导。
什么是 .NET Aspire?
.NET Aspire 是一个具有明确主张、适用于云环境的技术栈,用于构建可观测、可用于生产环境的分布式应用程序。它提供:
- 服务编排 - 通过依赖项管理协调多个项目和服务
- 服务发现 - 自动发现服务并建立服务间连接
- 遥测与可观测性 - 内置日志记录、指标和分布式跟踪
- 配置管理 - 集中式配置,支持强类型和机密信息
- 资源预配 - 与数据库、缓存、消息传递和云服务集成
- 开发者仪表板 - 本地监控和调试界面
何时使用此技能
在以下情况下使用此技能:
- 将 Aspire 添加到包含多个服务的现有 .NET 解决方案中
- 使用 Aspire 创建新的分布式应用程序
- 使微服务或分布式系统现代化,以便部署到云端
- 为本地开发和部署设置服务编排
- 集成云原生可观测性和配置模式
我需要什么组件/功能?
| 需求 | 资源 | 说明 |
|---|---|---|
| 整体结构 | 概述与设置 | 从分析到运行的分步实施指南 |
| 数据库、缓存、消息传递 | resources/components.md | 所有可用的 Aspire 组件包及示例 |
| 服务间通信 | resources/service-communication.md | 服务发现、HttpClient 模式、弹性 |
| 配置与机密信息 | resources/configuration-management.md | 环境设置、机密信息、功能标志 |
| 本地开发 | resources/local-development.md | 仪表板、调试、测试、运行状况检查 |
| 生产部署 | resources/deployment.md | Azure Container Apps、Kubernetes、Docker Compose |
概述与设置
核心概念
.NET Aspire 使用两个关键项目:
- AppHost - 编排服务和资源;提供开发者仪表板
- ServiceDefaults - 所有服务的共享配置(OpenTelemetry、运行状况检查、服务发现)
先决条件
# Install .NET Aspire workload
dotnet workload install aspire
# Verify installation
dotnet workload list # Should show "aspire"
# Docker Desktop (for container resources)
# Ensure it's running before launching AppHost
基本实施流程
1. 分析解决方案
- 确定服务(API、Web 应用、工作进程)
- 列出外部依赖项(数据库、Redis、消息队列)
- 确定服务通信模式
2. 创建 Aspire 项目
dotnet new aspire-apphost -n MyApp.AppHost
dotnet new aspire-servicedefaults -n MyApp.ServiceDefaults
dotnet sln add MyApp.AppHost/MyApp.AppHost.csproj
dotnet sln add MyApp.ServiceDefaults/MyApp.ServiceDefaults.csproj
3. 配置服务
- 为每个服务添加 ServiceDefaults 引用
- 在 Program.cs 中调用
builder.AddServiceDefaults() - 对 ASP.NET Core 服务调用
app.MapDefaultEndpoints()
4. 在 AppHost 中编排
var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache");
var database = builder.AddPostgres("postgres").AddDatabase("appdb");
var api = builder.AddProject<Projects.MyApi>("api")
.WithReference(database)
.WithReference(cache);
var web = builder.AddProject<Projects.MyWeb>("web")
.WithReference(api)
.WithExternalHttpEndpoints();
builder.Build().Run();
5. 更新服务通信
- 将硬编码 URL 替换为服务名称
- 使用与
builder.AddServiceDefaults()匹配的模式
6. 运行并验证
dotnet run --project MyApp.AppHost
# Opens dashboard at https://localhost:15001
关键决策
AppHost 项目命名:
- 约定:
[SolutionName].AppHost - 示例:对于名为 "ECommerceSystem" 的解决方案,创建 "ECommerceSystem.AppHost"
服务资源名称:
- 在 AppHost 中使用简短、描述性强的名称
- 示例:"api"、"web"、"worker"、"cache"、"database"
- 这些名称用于服务发现 URL
资源管理:
- 本地开发:使用 Aspire 管理的容器(PostgreSQL、Redis、RabbitMQ)
- 生产环境:由
azd自动预配 Azure 资源,或手动配置 - 连接字符串:自动注入;通常无需硬编码
服务发现设置:
- HttpClient URL 使用服务名称:使用
http://api,而非https://localhost:7001 - Aspire 负责处理服务间的路由和身份验证
- 外部服务使用显式端点配置
常见架构
Web API + 前端
var api = builder.AddProject<Projects.Api>("api")
.WithReference(database)
.WithExternalHttpEndpoints();
var web = builder.AddProject<Projects.Web>("web")
.WithReference(api)
.WithExternalHttpEndpoints();
使用消息队列的微服务
var messaging = builder.AddRabbitMQ("messaging");
var orderService = builder.AddProject<Projects.OrderService>("orders")
.WithReference(messaging);
var inventoryService = builder.AddProject<Projects.InventoryService>("inventory")
.WithReference(messaging);
多数据库系统
var postgres = builder.AddPostgres("postgres")
.AddDatabase("users")
.AddDatabase("products");
var mongo = builder.AddMongoDB("mongo")
.AddDatabase("orders");
var userApi = builder.AddProject<Projects.UserApi>("userapi")
.WithReference(postgres);
var orderApi = builder.AddProject<Projects.OrderApi>("orderapi")
.WithReference(mongo);
资源索引
如需详细的实现指导,请参阅:
- 组件 - 组件包和集成模式:
resources/components.md - 服务通信 - 服务发现和服务间调用:
resources/service-communication.md - 配置管理 - 密钥、环境变量、设置:
resources/configuration-management.md - 本地开发 - 控制面板功能、调试、运行状况检查:
resources/local-development.md - 部署 - Azure Container Apps、Kubernetes、Docker Compose:
resources/deployment.md
最佳实践
服务组织
- 让 AppHost 专注于组合,而非业务逻辑
- 使用 ServiceDefaults 处理跨领域关注点(可观测性、运行状况检查)
- 确保每个服务都能使用回退配置独立运行
资源管理
- 使用 Aspire 管理的资源,确保本地开发的一致性
- 在 AppHost 中通过
.WithReference()明确声明依赖项 - 为数据库添加数据持久化:
.WithDataVolume()
配置模式
- 开发环境:使用
appsettings.Development.json和.WithEnvironment() - 生产环境:使用 Azure Key Vault 或托管密钥
- 避免将密钥提交到源代码管理;在本地使用用户机密
可观测服务
- 通过 ServiceDefaults 启用 OpenTelemetry(自动)
- 使用开发者控制面板进行本地调试
- 在生产环境中将遥测数据导出到 Application Insights 或类似服务
常见问题与解决方案
服务无法通信
- 确认 AppHost 中的服务名称与 HttpClient URL 一致
- 确保所有服务都调用了
AddServiceDefaults() - 检查 ASP.NET 服务是否调用了
MapDefaultEndpoints()
未注入连接字符串
- 使用
builder.AddNpgsqlDbContext<>(),而非手动配置 - 确认 AppHost 和服务中的数据库/资源名称一致
- 确认项目文件中存在 ServiceDefaults 引用
控制面板无法启动
- 确保 Docker Desktop 正在运行
- 检查端口冲突(默认端口:15001)
- 确认运行的是 AppHost 项目,而非单个服务
运行状况检查失败
- 在控制面板中查看资源启动日志
- 检查本地计算机上的端口是否可用
- 确认 Docker 有足够的资源
入门检查清单
- 安装 .NET Aspire 工作负载并验证
- 分析解决方案结构并识别服务
- 创建 AppHost 和 ServiceDefaults 项目
- 为每个服务添加 ServiceDefaults 引用
- 使用
AddServiceDefaults()和MapDefaultEndpoints()更新服务的 Program.cs - 配置 AppHost 编排服务和资源
- 更新服务的 HttpClient URL,以使用服务发现名称
- 使用
dotnet run --project AppHost在本地测试 - 确认控制面板显示所有服务均在运行
- 配置部署目标(Azure、Kubernetes 等)
后续步骤
- 了解组件详情 → 请参阅
resources/components.md - 了解服务通信 → 请参阅
resources/service-communication.md - 了解配置 → 请参阅
resources/configuration-management.md - 了解本地开发 → 请参阅
resources/local-development.md - 了解部署 → 请参阅
resources/deployment.md
请记住:从单个服务开始,确认通信正常后,再逐步增加复杂性。在部署到生产环境之前,先使用控制面板在本地调试问题。
- 哪些项目应编排为服务?
- 需要哪些外部资源(数据库、Redis、存储等)?
- 应采用最精简的 Aspire 设置,还是包含其他组件?
- 是否已有 Docker 或编排配置?
2. 澄清问题
实施前,请与用户确认:
服务识别:
- “我已在您的解决方案中识别出 [X] 个服务:[list]。这些服务是否都应纳入 Aspire 编排?”
- “是否还应添加其他服务或项目?”
基础设施要求:
- “我看到有对 [database/Redis/etc.] 的引用。是否应由 Aspire 管理这些资源?”
- “您想使用容器资源还是连接字符串配置?”
Aspire 结构:
- “是否应创建一个名为 ‘[SolutionName].AppHost’ 的新 AppHost 项目,以及一个名为 ‘[SolutionName].ServiceDefaults’ 的 ServiceDefaults 项目?”
- “您是否偏好特定的命名约定?”
依赖关系:
- “哪些服务相互依赖?(这有助于设置服务发现)”
- “是否有任何启动顺序要求?”
3. 实施步骤
步骤 1:创建 Aspire 项目
创建 AppHost 项目:
dotnet new aspire-apphost -n [SolutionName].AppHost
AppHost 项目:
- 编排所有服务和资源
- 定义服务依赖项和配置
- 提供用于本地开发的开发者仪表板
- 包含用于组合应用程序的
Program.cs
创建 ServiceDefaults 项目:
dotnet new aspire-servicedefaults -n [SolutionName].ServiceDefaults
ServiceDefaults 项目:
- 提供共享的服务配置
- 配置 OpenTelemetry、运行状况检查和服务发现
- 应用于所有服务,以确保行为一致
将项目添加到解决方案:
dotnet sln add [SolutionName].AppHost/[SolutionName].AppHost.csproj
dotnet sln add [SolutionName].ServiceDefaults/[SolutionName].ServiceDefaults.csproj
步骤 2:配置服务项目
对于每个服务项目(API、Web 应用、Worker):
- 添加 ServiceDefaults 引用:
dotnet add [ServiceProject] reference [SolutionName].ServiceDefaults/[SolutionName].ServiceDefaults.csproj
- 更新 Program.cs 以注册服务默认值:
// At the top of Program.cs, after builder creation
var builder = WebApplication.CreateBuilder(args);
// Add this line
builder.AddServiceDefaults();
// ... rest of service configuration ...
var app = builder.Build();
// Add this line before app.Run()
app.MapDefaultEndpoints();
app.Run();
- 对于 Worker 服务,模式类似:
var builder = Host.CreateApplicationBuilder(args);
builder.AddServiceDefaults();
// ... service configuration ...
var host = builder.Build();
host.Run();
步骤 3:配置 AppHost
在 AppHost 中添加项目引用:
dotnet add [SolutionName].AppHost reference [ServiceProject1]/[ServiceProject1].csproj
dotnet add [SolutionName].AppHost reference [ServiceProject2]/[ServiceProject2].csproj
更新 AppHost Program.cs 以编排服务:
var builder = DistributedApplication.CreateBuilder(args);
// Add infrastructure resources
var cache = builder.AddRedis("cache");
var postgres = builder.AddPostgres("postgres")
.AddDatabase("appdb");
// Add services with dependencies
var apiService = builder.AddProject<Projects.MyApi>("apiservice")
.WithReference(postgres)
.WithReference(cache);
var webApp = builder.AddProject<Projects.MyWebApp>("webapp")
.WithReference(apiService)
.WithExternalHttpEndpoints();
builder.Build().Run();
常见资源方法:
.AddRedis("name")- Redis 缓存.AddPostgres("name").AddDatabase("dbname")- PostgreSQL.AddSqlServer("name").AddDatabase("dbname")- SQL Server.AddRabbitMQ("name")- RabbitMQ 消息传递.AddMongoDB("name").AddDatabase("dbname")- MongoDB.AddAzureStorage("name")- Azure Storage
服务配置方法:
.WithReference(resource)- 添加依赖项并注入连接信息.WithExternalHttpEndpoints()- 使服务可从外部访问.WithReplicas(count)- 运行多个实例.WithEnvironment("KEY", "value")- 添加环境变量.WithHttpsEndpoint(port: 7001)- 指定 HTTPS 端口
步骤 4:添加所需的 NuGet 包
Aspire 包由模板自动添加,但请确认以下内容:
AppHost 项目:
Aspire.Hosting.AppHost(通常通过 workload 引入)- 资源所需的其他托管包(例如
Aspire.Hosting.PostgreSQL)
ServiceDefaults 项目:
Microsoft.Extensions.Http.ResilienceMicrosoft.Extensions.ServiceDiscoveryOpenTelemetry.Exporter.OpenTelemetryProtocolOpenTelemetry.Extensions.HostingOpenTelemetry.Instrumentation.AspNetCoreOpenTelemetry.Instrumentation.HttpOpenTelemetry.Instrumentation.Runtime
服务项目:
Aspire.Npgsql.EntityFrameworkCore.PostgreSQL(如果使用 PostgreSQL)Aspire.StackExchange.Redis(如果使用 Redis)- 数据库、消息传递等所需的组件包
安装包:
dotnet add [Project] package [PackageName]
步骤 5:更新服务间通信
对于调用其他服务的服务,请使用服务发现:
之前(硬编码 URL):
builder.Services.AddHttpClient("apiservice", client =>
{
client.BaseAddress = new Uri("https://localhost:7001");
});
之后(服务发现):
builder.Services.AddHttpClient("apiservice", client =>
{
client.BaseAddress = new Uri("http://apiservice");
});
服务名称需与 AppHost 的 AddProject<>() 调用中的名称一致。
对于强类型 HttpClient:
builder.Services.AddHttpClient<IApiClient, ApiClient>(client =>
{
client.BaseAddress = new Uri("http://apiservice");
});
步骤 6:配置和连接字符串
资源连接字符串会自动注入。更新服务配置:
之前:
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
之后:
builder.AddNpgsqlDbContext<AppDbContext>("appdb");
连接名称(“appdb”)与 AppHost 中的数据库名称一致。
对于 Redis:
builder.AddRedisClient("cache");
步骤 7:验证和测试
运行 AppHost 项目:
dotnet run --project [SolutionName].AppHost
这将启动:
- Aspire 仪表板(通常位于 https://localhost:15001)
- 所有已配置的服务
- 所有资源容器(Redis、PostgreSQL 等)
验证:
- 仪表板显示所有服务均在运行
- 服务可通过服务发现进行通信
- 仪表板中显示遥测数据
- 资源连接正常工作
4. 高级配置
外部服务
对于不在解决方案中的服务:
var externalApi = builder.AddProject<Projects.ExternalApi>("external-api")
.WithHttpsEndpoint(port: 8001);
容器资源
在容器中运行服务:
var myApi = builder.AddContainer("myapi", "myapiimage")
.WithHttpEndpoint(port: 8000, targetPort: 80);
Azure 资源
对于托管在 Azure 上的资源:
var storage = builder.AddAzureStorage("storage")
.AddBlobs("blobs");
var keyVault = builder.AddAzureKeyVault("keyvault");
自定义资源
使用自定义资源扩展 Aspire:
var customResource = builder.AddResource(new CustomResource("name"))
.WithEndpoint("http", endpoint => endpoint.Port = 9000);
最佳实践
1. 服务组织
- 让 AppHost 专注于编排,而非业务逻辑
- 使用 ServiceDefaults 处理横切关注点
- 确保每项服务都能独立运行(并提供回退配置)
2. 资源管理
- 在本地开发中使用 Aspire 托管的资源
- 在生产部署中使用连接字符串
- 为数据库配置资源持久化(避免数据丢失)
3. 配置
- 使用
appsettings.Development.json设置本地覆盖项 - 将敏感数据保存在用户机密或密钥保管库中
- 使用特定于环境的配置
4. 依赖项
- 在 AppHost 中显式定义服务依赖项
- 使用
.WithReference()注入连接信息 - 考虑数据库迁移的启动顺序
5. 可观测性
- 利用内置的 OpenTelemetry 进行分布式追踪
- 使用仪表板进行本地调试
- 为每项服务配置适当的日志级别
常见模式
API 网关模式
var apiGateway = builder.AddProject<Projects.ApiGateway>("gateway")
.WithExternalHttpEndpoints();
var serviceA = builder.AddProject<Projects.ServiceA>("servicea");
var serviceB = builder.AddProject<Projects.ServiceB>("serviceb");
apiGateway.WithReference(serviceA).WithReference(serviceB);
带消息队列的工作进程
var messaging = builder.AddRabbitMQ("messaging");
var worker = builder.AddProject<Projects.Worker>("worker")
.WithReference(messaging);
var api = builder.AddProject<Projects.Api>("api")
.WithReference(messaging);
带后端 API 的 Web 应用
var cache = builder.AddRedis("cache");
var database = builder.AddPostgres("postgres").AddDatabase("appdb");
var api = builder.AddProject<Projects.Api>("api")
.WithReference(database)
.WithReference(cache);
var web = builder.AddProject<Projects.Web>("web")
.WithReference(api)
.WithExternalHttpEndpoints();
故障排除
服务发现无法正常工作
- 确保在服务的 Program.cs 中调用
builder.AddServiceDefaults() - 确认 HttpClient 中的服务名称与 AppHost 的 AddProject 名称一致
- 检查是否为 ASP.NET 服务调用了
app.MapDefaultEndpoints()
未注入连接字符串
- 确认 AppHost 和服务配置中的资源名称一致
- 使用
builder.AddNpgsqlDbContext<>(),而非手动调用 AddDbContext - 确认存在 ServiceDefaults 引用
无法访问仪表板
- 检查 AppHost 是否正在运行(而非单独的服务)
- 确认端口未被阻止(默认值:15001)
- 在 AppHost 控制台输出中查找仪表板 URL
资源无法启动
- 确保 Docker Desktop 正在运行(适用于容器资源)
- 检查端口是否与现有服务冲突
- 查看 AppHost 控制台中的启动错误
要修改的文件
将 Aspire 添加到现有解决方案时,预计需要修改:
- 解决方案文件 (.sln) - 添加 AppHost 和 ServiceDefaults 项目
- 每项服务的 Program.cs - 添加服务默认值注册
- 每项服务的 .csproj - 添加 ServiceDefaults 引用
- AppHost/Program.cs - 定义编排和资源
- 服务配置 - 将硬编码的 URL 替换为服务发现
- 数据库配置 - 使用 Aspire 组件方法
先决条件
确保已安装以下内容:
- .NET 8.0 SDK 或更高版本
- .NET Aspire 工作负载:
dotnet workload install aspire - Docker Desktop(适用于容器资源)
验证安装:
dotnet workload list
输出中应显示已安装的工作负载包含“aspire”。
摘要检查清单
实现 Aspire 后,请验证:
- 已创建 AppHost 项目并将其添加到解决方案
- 已创建 ServiceDefaults 项目并将其添加到解决方案
- 所有服务项目都引用了 ServiceDefaults
- 服务的 Program.cs 文件调用了
AddServiceDefaults()和MapDefaultEndpoints() - AppHost Program.cs 使用恰当的依赖关系编排所有服务
- 服务间通信使用服务发现(而非硬编码 URL)
- 数据库和缓存连接使用 Aspire 组件方法
- AppHost 成功运行并启动仪表板
- 所有服务均显示在仪表板中,且状态健康
- 显示了跨服务请求的遥测数据
其他资源
有关特定组件和模式的详细信息,请参阅:
resources/components.md- Aspire 组件包和配置resources/deployment.md- 将 Aspire 应用部署到生产环境
示例输出
完成后,解决方案结构应如下所示:
MySolution/
├── MySolution.sln
├── MySolution.AppHost/
│ ├── Program.cs # Orchestration configuration
│ ├── MySolution.AppHost.csproj
│ └── appsettings.json
├── MySolution.ServiceDefaults/
│ ├── Extensions.cs # Service defaults implementation
│ └── MySolution.ServiceDefaults.csproj
├── MySolution.Api/
│ ├── Program.cs # Calls AddServiceDefaults()
│ └── MySolution.Api.csproj # References ServiceDefaults
├── MySolution.Web/
│ ├── Program.cs # Calls AddServiceDefaults()
│ └── MySolution.Web.csproj # References ServiceDefaults
└── MySolution.Worker/
├── Program.cs # Calls AddServiceDefaults()
└── MySolution.Worker.csproj # References ServiceDefaults
运行 dotnet run --project MySolution.AppHost 会启动所有服务,并打开仪表板以监控和调试分布式应用程序。