名称: dotnet-aspire 描述: 为现有 .NET 解决方案添加 .NET Aspire 云原生编排。分析解决方案结构以识别服务(APIs、web 应用、工作者),创建 AppHost 和 ServiceDefaults 项目,配置服务发现,添加 NuGet 包,并设置分布式应用程序编排。适用于将 Aspire 添加到 .NET 解决方案或创建新的云就绪分布式应用程序。 许可证: MIT 元数据: 版本: “2.0” 领域: 基础设施 触发词: Aspire, .NET Aspire, AppHost, ServiceDefaults, 服务发现, 云原生, 分布式应用, 编排, 遥测, 可观测性 角色: 专家 范围: 实施 输出格式: 代码 相关技能: dotnet-core-expert, microservices-architect, kubernetes-specialist
.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 容器应用、Kubernetes、Docker Compose |
概述与设置
核心概念
.NET Aspire 使用两个关键项目:
- AppHost - 编排服务和资源;提供开发者仪表板
- ServiceDefaults - 所有服务的共享配置(OpenTelemetry、健康检查、服务发现)
先决条件
# 安装 .NET Aspire 工作负载
dotnet workload install aspire
# 验证安装
dotnet workload list # 应显示 "aspire"
# Docker Desktop(用于容器资源)
# 在启动 AppHost 前确保其运行
基本实施流程
1. 分析解决方案
- 识别服务(APIs、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
# 在 https://localhost:15001 打开仪表板
关键决策
AppHost 项目命名:
- 惯例:
[解决方案名称].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 容器应用、Kubernetes、Docker Compose:
resources/deployment.md
最佳实践
服务组织
- 保持 AppHost 专注于组合,而非业务逻辑
- 使用 ServiceDefaults 处理横切关注点(可观测性、健康检查)
- 确保每个服务独立运行,具有后备配置
资源管理
- 使用 Aspire 管理的资源确保本地开发一致性
- 通过
.WithReference()在 AppHost 中定义显式依赖 - 为数据库添加数据持久化:
.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] 个服务:[列表]。是否所有这些都应包含在 Aspire 编排中?”
- “是否有任何额外的服务或项目应被添加?”
基础设施需求:
- “我看到对 [数据库/Redis/等] 的引用。是否应由 Aspire 管理这些资源?”
- “您希望使用容器资源还是连接字符串配置?”
Aspire 结构:
- “我应该创建一个名为 ‘[解决方案名称].AppHost’ 的新 AppHost 项目和名为 ‘[解决方案名称].ServiceDefaults’ 的 ServiceDefaults 项目吗?”
- “您偏好特定的命名惯例吗?”
依赖关系:
- “哪些服务相互依赖?(这有助于设置服务发现)”
- “是否有任何启动顺序要求?”
3. 实施步骤
步骤 1:创建 Aspire 项目
创建 AppHost 项目:
dotnet new aspire-apphost -n [解决方案名称].AppHost
AppHost 项目:
- 编排所有服务和资源
- 定义服务依赖和配置
- 为本地开发提供开发者仪表板
- 包含应用程序组合的
Program.cs
创建 ServiceDefaults 项目:
dotnet new aspire-servicedefaults -n [解决方案名称].ServiceDefaults
ServiceDefaults 项目:
- 提供共享服务配置
- 配置 OpenTelemetry、健康检查和服务发现
- 应用于所有服务以确保一致行为
将项目添加到解决方案:
dotnet sln add [解决方案名称].AppHost/[解决方案名称].AppHost.csproj
dotnet sln add [解决方案名称].ServiceDefaults/[解决方案名称].ServiceDefaults.csproj
步骤 2:配置服务项目
对于每个服务项目(API、Web 应用、工作者):
- 添加 ServiceDefaults 引用:
dotnet add [服务项目] reference [解决方案名称].ServiceDefaults/[解决方案名称].ServiceDefaults.csproj
- 更新 Program.cs 以注册服务默认值:
// 在 Program.cs 顶部,构建器创建后
var builder = WebApplication.CreateBuilder(args);
// 添加此行
builder.AddServiceDefaults();
// ... 服务配置的其余部分 ...
var app = builder.Build();
// 在 app.Run() 前添加此行
app.MapDefaultEndpoints();
app.Run();
- 对于工作者服务,模式类似:
var builder = Host.CreateApplicationBuilder(args);
builder.AddServiceDefaults();
// ... 服务配置 ...
var host = builder.Build();
host.Run();
步骤 3:配置 AppHost
在 AppHost 中添加项目引用:
dotnet add [解决方案名称].AppHost reference [服务项目1]/[服务项目1].csproj
dotnet add [解决方案名称].AppHost reference [服务项目2]/[服务项目2].csproj
更新 AppHost Program.cs 以编排服务:
var builder = DistributedApplication.CreateBuilder(args);
// 添加基础设施资源
var cache = builder.AddRedis("cache");
var postgres = builder.AddPostgres("postgres")
.AddDatabase("appdb");
// 添加带依赖的服务
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("名称")- Redis 缓存.AddPostgres("名称").AddDatabase("数据库名")- PostgreSQL.AddSqlServer("名称").AddDatabase("数据库名")- SQL Server.AddRabbitMQ("名称")- RabbitMQ 消息传递.AddMongoDB("名称").AddDatabase("数据库名")- MongoDB.AddAzureStorage("名称")- Azure 存储
服务配置方法:
.WithReference(资源)- 添加依赖并注入连接信息.WithExternalHttpEndpoints()- 使服务可从外部访问.WithReplicas(数量)- 运行多个实例.WithEnvironment("键", "值")- 添加环境变量.WithHttpsEndpoint(端口: 7001)- 指定 HTTPS 端口
步骤 4:添加所需的 NuGet 包
模板自动添加 Aspire 包,但验证:
AppHost 项目:
Aspire.Hosting.AppHost(通常通过工作负载包含)- 资源的额外托管包(例如,
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 [项目] package [包名]
步骤 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<>() 调用的名称匹配。
对于类型化 HttpClients:
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 [解决方案名称].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);
Web 应用与后端 API
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 # 编排配置
│ ├── MySolution.AppHost.csproj
│ └── appsettings.json
├── MySolution.ServiceDefaults/
│ ├── Extensions.cs # 服务默认值实现
│ └── MySolution.ServiceDefaults.csproj
├── MySolution.Api/
│ ├── Program.cs # 调用 AddServiceDefaults()
│ └── MySolution.Api.csproj # 引用 ServiceDefaults
├── MySolution.Web/
│ ├── Program.cs # 调用 AddServiceDefaults()
│ └── MySolution.Web.csproj # 引用 ServiceDefaults
└── MySolution.Worker/
├── Program.cs # 调用 AddServiceDefaults()
└── MySolution.Worker.csproj # 引用 ServiceDefaults
运行 dotnet run --project MySolution.AppHost 启动所有服务并打开仪表板,以监控和调试分布式应用程序。