

第一章:Aspire 与 .NET 10 概述
1.1 什么是 .NET Aspire?
.NET Aspire 是微软于 2023 年底正式推出的一套云原生应用开发堆栈,专为构建可观察、可靠、可部署的分布式应用程序而设计。它不是一个新的框架,而是一组工具、模板、库和最佳实践的集合,旨在简化现代云原生应用的开发流程。
Aspire 的核心目标包括:
- 简化微服务架构的搭建:自动处理服务发现、配置、健康检查等。
- 内置可观测性:集成 OpenTelemetry,开箱即用的日志、指标、追踪。
- 本地开发体验一致:通过 Aspire Dashboard 提供统一的本地调试视图。
- 无缝对接云平台:支持 Azure Container Apps、Kubernetes、Docker Compose 等部署目标。
- 声明式资源编排:使用 C# 编写基础设施即代码(Infrastructure as Code)。
注意:Aspire 要求 .NET 8 或更高版本。随着 .NET 10(预计 2025 年 11 月正式发布)的到来,Aspire 将获得更强的性能、更完善的 API 和更深度的集成。
1.2 .NET 10 新特性前瞻(截至 2025 年)
虽然 .NET 10 尚未完全发布(当前为预览阶段),但根据官方路线图和社区反馈,以下特性将显著影响 Aspire 开发:
✅ 性能增强
- 更快的 JIT 编译器(RyuJIT 改进)
- 更低的内存分配(减少 GC 压力)
- 原生 AOT(Ahead-of-Time)进一步优化,适用于容器化部署
✅ 云原生原语增强
- System.Cloud 命名空间引入(标准化云服务抽象)
- 内置对 Dapr(Distributed Application Runtime)的深度支持
- 改进的 HttpClient 连接池与重试策略
✅ 开发者体验升级
- Visual Studio 2025 与 VS Code 插件深度集成 Aspire
- dotnet aspire CLI 工具功能扩展(如一键部署到 Azure)
- 更智能的热重载(Hot Reload)支持多项目联动
✅ 安全性强化
- 默认启用 HTTPS 重定向和 HSTS
- 内置密钥管理(Key Vault 集成简化)
- 自动依赖漏洞扫描(通过 NuGet 审计)
1.3 Aspire 项目结构解析
一个典型的 Aspire 解决方案包含三个核心项目:
| 项目类型 |
作用 |
示例名称 |
| App Host |
应用主机,定义所有服务、数据库、缓存等资源的拓扑结构 |
MyApp.AppHost |
| Service Projects |
实际业务微服务(Web API、Worker 等) |
MyApp.ApiService, MyApp.Worker |
| Web Frontend (可选) |
前端 Web 应用(Blazor、MVC、React 等) |
MyApp.Web |
所有项目均基于 .NET 10 SDK 构建。
示例:创建第一个 Aspire 项目
# 安装 Aspire 工作负载(需 .NET 8+ SDK)
dotnet workload install aspire
# 创建 Aspire Starter 项目
dotnet new aspire-starter -o MyApp
cd MyApp
生成的目录结构如下:
MyApp/
├── MyApp.AppHost/ # 应用主机
├── MyApp.ServiceDefaults/ # 共享服务配置(日志、健康检查等)
├── MyApp.ApiService/ # 示例 Web API 服务
└── MyApp.Web/ # Blazor 前端
1.4 Aspire 核心组件介绍
1.4.1 App Host(应用主机)
- 使用 C# 代码声明式定义整个应用拓扑。
- 自动启动依赖服务(如 PostgreSQL、Redis、RabbitMQ)。
- 支持本地开发(通过 Docker)和云部署。
// MyApp.AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);
// 添加 PostgreSQL 数据库
var postgres = builder.AddPostgres("mydb");
// 添加 Redis 缓存
var cache = builder.AddRedis("cache");
// 添加 Web API 服务,并注入数据库连接
var api = builder.AddProject<Projects.MyApp_ApiService>("api")
.WithReference(postgres)
.WithReference(cache);
// 添加前端 Web 应用
builder.AddProject<Projects.MyApp_Web>("web")
.WithReference(api);
builder.Build().Run();
.WithReference() 自动注入连接字符串或客户端配置到目标服务。
1.4.2 Service Defaults(服务默认配置)
这是一个共享类库,用于统一配置:
- OpenTelemetry(日志、指标、追踪)
- 健康检查(Health Checks)
- HTTP 客户端命名策略
- 最小 API 或 MVC 的通用中间件
// MyApp.ServiceDefaults/Extensions.cs
public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
{
builder.ConfigureOpenTelemetry();
builder.AddHealthChecks();
return builder;
}
各服务只需调用:
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults(); // 统一配置
1.4.3 Aspire Dashboard
1.5 为什么选择 Aspire + .NET 10?
| 场景 |
传统方式痛点 |
Aspire + .NET 10 解决方案 |
| 多服务本地调试 |
需手动启动多个容器/进程 |
dotnet run 一键启动全部 |
| 配置管理混乱 |
appsettings.json 分散、易错 |
App Host 统一注入 |
| 可观测性缺失 |
需手动集成 Prometheus/Grafana |
内置 OpenTelemetry |
| 云部署复杂 |
YAML/K8s 配置繁琐 |
C# 代码定义部署拓扑 |
| 团队协作困难 |
环境不一致 |
开发者共享同一套声明式配置 |
1.6 本章小结
本章介绍了:
- .NET Aspire 是微软为云原生应用打造的端到端开发堆栈;
- .NET 10 将带来性能、安全性和开发者体验的重大升级;
- Aspire 项目由 App Host、Service Projects 和共享配置组成;
- 核心优势在于简化分布式系统开发,让开发者聚焦业务逻辑。
第二章:开发环境搭建与第一个 Aspire 应用
在本章中,我们将从零开始搭建完整的 .NET Aspire 开发环境,并创建、运行一个包含 Web API 和前端界面的最小可行 Aspire 应用。所有操作均基于 .NET 10 预览版(或正式版) 和 Windows / macOS / Linux 通用流程。
2.1 系统要求与前置条件
支持的操作系统
- Windows 10/11(建议 WSL2 用于容器开发)
- macOS Monterey (12.0) 或更高
- Ubuntu 22.04 LTS / Fedora 38 / 其他主流 Linux 发行版
必需软件
| 软件 |
版本要求 |
说明 |
| .NET SDK |
10.0.x(预览版或正式版) |
核心开发运行时 |
| Docker Desktop |
24.0+ |
用于本地运行数据库、缓存等依赖服务 |
| Visual Studio 2025(可选)或 VS Code |
最新版 |
推荐安装 C# Dev Kit 和 Aspire 扩展 |
| Git |
2.35+ |
用于版本控制和模板拉取 |
💡 提示:Aspire 重度依赖容器化技术,Docker 必须正常运行。
2.2 安装 .NET 10 SDK
方法一:通过官方安装包(推荐)
访问 .NET 下载页(截至 2025 年 11 月,.NET 10 已正式发布),下载对应平台的 SDK 安装包。
验证安装:
dotnet --version
# 输出应为:10.0.xxxxx
方法二:使用脚本安装(Linux/macOS)
curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 10.0
export PATH=$HOME/.dotnet:$PATH
Windows 用户可使用 PowerShell 脚本:
Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1
.\dotnet-install.ps1 -Channel 10.0
2.3 安装 Aspire 工作负载
Aspire 作为 .NET 的“工作负载”(Workload)分发,需单独安装:
dotnet workload install aspire
⏱️ 首次安装可能需要几分钟,会下载约 500MB 的组件。
验证是否安装成功:
dotnet new list | grep aspire
应看到如下模板:
- aspire-starter:基础多项目模板
- aspire-empty:空 App Host 模板
- aspire-service:单个服务模板
2.4 安装并配置 Docker Desktop
- 从 Docker 官网 下载并安装。
- 启动 Docker Desktop,确保状态为 “Running”。
- (可选)在设置中启用 “Use Rosetta for x86/amd64 emulation on Apple Silicon”(仅 M1/M2 Mac)。
验证:
docker --version
# Docker version 24.0.7, build afdd53b
docker run hello-world
# 应输出 “Hello from Docker!”
⚠️ 注意:Windows 用户若使用 WSL2 后端,需确保 WSL2 已启用且默认发行版为 Ubuntu 22.04+。
2.5 创建第一个 Aspire 项目
我们使用官方 aspire-starter 模板快速生成项目骨架:
dotnet new aspire-starter -o ECommercePlatform
cd ECommercePlatform
项目结构如下:
ECommercePlatform/
├── ECommercePlatform.AppHost/ # 应用主机(编排中心)
├── ECommercePlatform.ServiceDefaults/ # 共享服务配置
├── ECommercePlatform.ApiService/ # 示例 Web API(天气预报)
└── ECommercePlatform.Web/ # Blazor Server 前端
2.6 项目详解与代码剖析
Program.cs 是整个应用的“蓝图”:
var builder = DistributedApplication.CreateBuilder(args);
// 添加 PostgreSQL 数据库(本地由 Docker 启动)
var postgres = builder.AddPostgres("postgresdb");
// 添加 Redis 缓存
var redis = builder.AddRedis("redis");
// 添加 API 服务,并注入数据库和缓存依赖
var apiService = builder.AddProject<Projects.ECommercePlatform_ApiService>("apiservice")
.WithReference(postgres)
.WithReference(redis);
// 添加 Web 前端,并引用 API 服务
builder.AddProject<Projects.ECommercePlatform_Web>("webfrontend")
.WithReference(apiService);
builder.Build().Run();
关键点:
.AddPostgres() 和 .AddRedis() 会自动在本地启动对应容器。
.WithReference() 实现服务间安全通信和配置注入(如连接字符串)。
2.6.2 ApiService 项目
这是一个标准的 .NET 10 Web API 项目,但集成了 Service Defaults:
var builder = WebApplication.CreateBuilder(args);
// 应用共享配置(日志、健康检查、遥测等)
builder.AddServiceDefaults();
// 注册 PostgreSQL 上下文
builder.AddNpgsqlDbContext<ProductContext>("postgresdb");
// 注册 Redis 客户端
builder.AddRedisClient("redis");
var app = builder.Build();
// 启用健康检查端点
app.MapDefaultHealthChecks();
// 示例 API
app.MapGet("/products", async (ProductContext db) =>
{
return await db.Products.ToListAsync();
});
app.Run();
✅ 注意:AddNpgsqlDbContext 和 AddRedisClient 是 Aspire 提供的扩展方法,自动从 App Host 注入连接信息。
2.6.3 Web 前端项目(Blazor Server)
前端通过 HTTP 调用 ApiService:
@page "/products"
@inject HttpClient Http
<h3>Products</h3>
@if (products == null)
{
<p>Loading...</p>
}
else
{
<ul>
@foreach (var p in products)
{
<li>@p.Name - $@p.Price</li>
}
</ul>
}
@code {
private Product[]? products;
protected override async Task OnInitializedAsync()
{
products = await Http.GetFromJsonAsync<Product[]>("http://apiservice/products");
}
}
🔗 关键:http://apiservice 是 Aspire 自动解析的服务名(基于项目名),无需硬编码 IP 或端口。
2.7 运行 Aspire 应用
在项目根目录执行:
dotnet run --project ECommercePlatform.AppHost
首次运行时,Aspire 会:
- 构建所有项目;
- 启动 PostgreSQL 和 Redis 容器;
- 启动 ApiService 和 Web 前端;
- 自动打开 Aspire Dashboard(默认 http://localhost:17100)。
你将看到类似以下输出:
info: Aspire.Hosting.Dcp.DcpHostService[0]
Starting application...
info: Aspire.Hosting.Dcp.DcpHostService[0]
Dashboard running on: http://localhost:17100
info: Aspire.Hosting.Dcp.DcpHostService[0]
apiservice running on: http://localhost:15123
info: Aspire.Hosting.Dcp.DcpHostService[0]
webfrontend running on: http://localhost:15124
访问各组件
2.8 Aspire Dashboard 功能演示
打开 Dashboard,你会看到:
1. 资源拓扑图
- 可视化展示所有服务、数据库、缓存及其依赖关系。
- 点击任一节点可查看详细信息。
2. 实时日志流
- 聚合所有服务的日志,支持按服务过滤。
- 自动高亮错误和警告。
3. 指标监控
- CPU、内存、请求率、延迟等。
- 基于 OpenTelemetry + Prometheus 抓取。
4. 分布式追踪
- 点击一个 HTTP 请求,可查看跨服务的完整调用链(Trace)。
- 显示每个 Span 的耗时和标签。
🌟 这是 Aspire 最强大的功能之一——无需配置,开箱即用的可观测性。
2.9 常见问题排查
❌ 问题1:Docker 未运行,报错 “Container engine not found”
解决:启动 Docker Desktop,确保状态为绿色。
❌ 问题2:端口被占用(如 5432)
解决:Aspire 默认使用随机端口映射本地容器。若需固定端口,可在 App Host 中指定:
builder.AddPostgres("postgresdb").WithPort(5432);
❌ 问题3:服务无法互相访问(如 Web 找不到 apiservice)
原因:Aspire 使用内部 DNS 解析服务名。确保:
- 所有服务均由 App Host 启动;
- 不手动修改 HttpClient.BaseAddress。
❌ 问题4:.NET 10 SDK 未识别
解决:检查 global.json 是否锁定旧版本,或运行 dotnet --list-sdks 确认 10.0.x 存在。
2.10 本章小结
本章完成了:
- 安装 .NET 10 SDK 和 Aspire 工作负载;
- 配置 Docker Desktop 开发环境;
- 使用模板创建完整的 Aspire 多项目解决方案;
- 理解 App Host、服务项目、共享配置的角色;
- 成功运行应用并使用 Aspire Dashboard 进行调试。
你现在已具备开发 Aspire 应用的基础能力!
第三章:Aspire 中的服务通信机制
在云原生和微服务架构中,服务间通信是核心挑战之一。传统方式常涉及手动管理服务发现、负载均衡、重试、超时、认证等问题,容易出错且维护成本高。而 .NET Aspire 通过深度集成 .NET 10 的新特性与现代通信协议,为开发者提供了一套安全、可靠、可观测的服务调用体系。
本章将系统讲解:
- HTTP 客户端的自动配置与命名策略
- gRPC 在 Aspire 中的最佳实践
- 消息队列(RabbitMQ / Kafka)集成
- 服务间认证与安全通信
- 分布式上下文传播(Trace ID 透传)
3.1 HTTP 通信:HttpClient 的智能注入
在 Aspire 中,不推荐手动创建 HttpClient 实例。取而代之的是使用 .NET 10 新增的 IHttpClientFactory 增强机制 与 Aspire 的引用注入系统。
3.1.1 服务引用与自动 DNS 解析
回顾第二章中的 App Host 配置:
var api = builder.AddProject<Projects.OrderService>("orderservice");
builder.AddProject<Projects.WebFrontend>("web")
.WithReference(api);
当 WebFrontend 引用 orderservice 后,Aspire 会:
- 在本地开发环境中,为 orderservice 分配一个内部 DNS 名称(即 "orderservice");
- 自动配置 HttpClient,使其能通过该名称解析到正确的 IP 和端口;
- 注入必要的遥测上下文(如 Trace ID)。
3.1.2 在服务中使用命名 HttpClient
在 WebFrontend 的 Program.cs 中:
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// 注册命名 HttpClient,指向 "orderservice"
builder.Services.AddHttpClient("OrderApiClient", client =>
{
client.BaseAddress = new Uri("http://orderservice"); // 关键:使用服务名
});
var app = builder.Build();
app.MapDefaultHealthChecks();
在 Razor 页面或控制器中使用:
public class OrderModel : PageModel
{
private readonly HttpClient _httpClient;
public OrderModel(IHttpClientFactory factory)
{
_httpClient = factory.CreateClient("OrderApiClient");
}
public async Task OnGet()
{
var orders = await _httpClient.GetFromJsonAsync<Order[]>("api/orders");
}
}
✅ 优势:无需关心服务实际运行在哪台机器、哪个端口——Aspire 自动处理服务发现。
3.1.3 .NET 10 新特性:AddHttpClient<T> 泛型简化
.NET 10 引入了更简洁的泛型注册方式,结合 Aspire 更高效:
// 定义客户端接口
public interface IOrderApiClient
{
Task<Order[]> GetOrdersAsync();
}
// 实现类
public class OrderApiClient(HttpClient httpClient) : IOrderApiClient
{
public async Task<Order[]> GetOrdersAsync() =>
await httpClient.GetFromJsonAsync<Order[]>("api/orders");
}
// 注册
builder.Services.AddHttpClient<IOrderApiClient, OrderApiClient>(client =>
{
client.BaseAddress = new Uri("http://orderservice");
});
现在可直接注入 IOrderApiClient,代码更清晰、测试更方便。
3.2 gRPC 通信支持
Aspire 对 gRPC 提供一等公民支持,适用于高性能、低延迟场景(如内部服务调用)。
3.2.1 创建 gRPC 服务项目
dotnet new grpc -o InventoryService
定义 .proto 文件:
syntax = "proto3";
package inventory;
service InventoryService {
rpc GetStock(GetStockRequest) returns (GetStockResponse);
}
message GetStockRequest { string productId = 1; }
message GetStockResponse { int32 stock = 1; }
生成 C# 代码后,实现服务:
public class InventoryServiceImpl : InventoryService.InventoryServiceBase
{
public override Task<GetStockResponse> GetStock(
GetStockRequest request, ServerCallContext context)
{
return Task.FromResult(new GetStockResponse { Stock = 100 });
}
}
3.2.2 在 App Host 中注册 gRPC 服务
var inventory = builder.AddProject<Projects.InventoryService>("inventory")
.WithHttpEndpoint(port: 5001, isProxied: true); // gRPC 通常走 HTTP/2
⚠️ 注意:gRPC 需要 HTTP/2,确保端点启用 TLS 或在本地开发中允许明文 HTTP/2(.NET 10 默认支持)。
3.2.3 客户端调用 gRPC 服务
在 OrderService 中:
// 注册 gRPC 客户端
builder.Services.AddGrpcClient<InventoryService.InventoryServiceClient>(o =>
{
o.Address = new Uri("http://inventory:5001");
});
// 使用
public class OrderService
{
private readonly InventoryService.InventoryServiceClient _inventoryClient;
public OrderService(InventoryService.InventoryServiceClient client)
{
_client = client;
}
public async Task<bool> CheckStock(string productId)
{
var response = await _client.GetStockAsync(new GetStockRequest { ProductId = productId });
return response.Stock > 0;
}
}
Aspire 会自动处理:
- 服务地址解析
- 连接池管理
- OpenTelemetry 追踪埋点(gRPC 方法自动记录为 Span)
3.3 消息队列集成:RabbitMQ 与 Kafka
异步通信是解耦服务的关键。Aspire 内置对主流消息中间件的支持。
3.3.1 添加 RabbitMQ 依赖
在 App Host 中:
var rabbit = builder.AddRabbitMQ("rabbitmq");
// 订单服务发布消息
var orderService = builder.AddProject<Projects.OrderService>("orderservice")
.WithReference(rabbit);
// 库存服务消费消息
builder.AddProject<Projects.InventoryWorker>("inventoryworker")
.WithReference(rabbit);
3.3.2 发布消息(OrderService)
使用 .NET 10 的 Microsoft.Extensions.Azure 或 RabbitMQ.Client:
// Program.cs
builder.AddRabbitMQClient("rabbitmq"); // 注入连接
// OrderController.cs
public class OrderController : ControllerBase
{
private readonly IConnection _rabbitConn;
public OrderController(IConnection rabbitConn) => _rabbitConn = rabbitConn;
[HttpPost]
public async Task<IActionResult> CreateOrder(CreateOrderDto dto)
{
// 业务逻辑...
using var channel = _rabbitConn.CreateChannel();
channel.QueueDeclare("order.created", durable: true, exclusive: false, autoDelete: false);
var body = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(dto));
channel.BasicPublish("", "order.created", body: body);
return Ok();
}
}
3.3.3 消费消息(InventoryWorker)
创建一个后台服务 Worker:
public class InventoryWorker : BackgroundService
{
private readonly IConnection _rabbitConn;
public InventoryWorker(IConnection rabbitConn) => _rabbitConn = rabbitConn;
protected override async Task ExecuteAsync(CancellationToken ct)
{
using var channel = _rabbitConn.CreateChannel();
channel.QueueDeclare("order.created", durable: true);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += async (model, ea) =>
{
var body = ea.Body.ToArray();
var order = JsonSerializer.Deserialize<CreateOrderDto>(body);
// 更新库存逻辑...
channel.BasicAck(ea.DeliveryTag, multiple: false);
};
channel.BasicConsume("order.created", autoAck: false, consumer);
await Task.Delay(Timeout.Infinite, ct);
}
}
✅ Aspire 优势:RabbitMQ 容器由 App Host 自动启动,连接字符串自动注入,无需硬编码。
3.3.4 Kafka 支持(.NET 10 + Aspire)
Aspire 同样支持 Kafka:
var kafka = builder.AddKafka("kafka");
使用 Confluent.Kafka 客户端,配合 .NET 10 的 IHostedService 实现生产/消费。
3.4 服务间安全通信
3.4.1 本地开发:默认无加密(但隔离)
Aspire 在本地使用 Docker 网络,默认服务间通信在私有网络内,无需 HTTPS。但生产环境必须启用 TLS。
3.4.2 生产环境:启用 mTLS(双向 TLS)
Aspire 支持与 Dapr 或 Service Mesh(如 Linkerd) 集成实现 mTLS。也可手动配置:
// 在 ApiService 中强制 HTTPS
app.UseHttpsRedirection();
app.UseAuthentication(); // 若需身份验证
// 在客户端启用证书验证(高级场景)
builder.Services.AddHttpClient("SecureApi", client =>
{
client.BaseAddress = new Uri("https://secureapi");
}).ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) =>
{
// 自定义证书验证逻辑(仅用于测试!)
return true; // ⚠️ 生产环境应验证证书链
}
};
});
🔒 推荐:在 Azure 上部署时,使用 Azure Service Fabric Mesh 或 Container Apps 自动提供 mTLS。
3.5 分布式上下文传播(Trace ID 透传)
这是 Aspire 可观测性的核心!
3.5.1 自动 Trace 传播
当你在 Web 前端发起请求:
- Aspire 自动生成一个 Trace ID;
- 调用 HttpClient 时,自动在 Header 中添加 traceparent;
- ApiService 收到请求后,将其作为子 Span 记录;
- 所有日志自动关联该 Trace ID。
无需任何代码!得益于:
- OpenTelemetry .NET SDK
- Aspire 的 AddServiceDefaults() 中已启用 TraceContextPropagator
3.5.2 手动传递自定义上下文
若需传递用户 ID、租户 ID 等:
// 前端
var request = new HttpRequestMessage(HttpMethod.Get, "http://orderservice/api/orders");
request.Headers.Add("X-Tenant-Id", "tenant-123");
await _httpClient.SendAsync(request);
在 ApiService 中读取:
app.Use(async (context, next) =>
{
if (context.Request.Headers.TryGetValue("X-Tenant-Id", out var tenantId))
{
// 将 tenantId 存入 AsyncLocal 或 ILogger scope
using var scope = logger.BeginScope("TenantId: {TenantId}", tenantId);
await next();
}
});
📊 在 Aspire Dashboard 的 Trace 视图中,可看到完整的调用链和自定义标签。
3.6 本章小结
本章深入探讨了 Aspire 中的服务通信机制:
- HTTP:通过服务引用和命名 HttpClient 实现自动服务发现;
- gRPC:高性能 RPC 调用,无缝集成;
- 消息队列:RabbitMQ/Kafka 异步解耦,App Host 统一管理;
- 安全性:本地开发简化,生产环境支持 mTLS;
- 可观测性:OpenTelemetry 自动传播 Trace ID,实现端到端追踪。
这些能力让开发者 无需关注底层网络细节,专注业务逻辑。
第四章:数据持久化与数据库集成
在现代云原生应用中,数据是核心资产。Aspire 不仅简化了服务通信,还为数据库集成提供了统一、安全、可观测的解决方案。本章将深入讲解如何在 Aspire + .NET 10 项目中高效使用主流数据库,包括关系型(PostgreSQL、SQL Server)和非关系型(MongoDB),并涵盖 Entity Framework Core 10 的新特性、连接管理、迁移策略及性能优化。
4.1 Aspire 数据库集成的核心理念
Aspire 对数据库的支持遵循三大原则:
- 声明式资源定义:在 App Host 中用 C# 代码声明数据库类型、版本、配置,无需手动编写 docker-compose.yml 或 Kubernetes YAML。
- 自动连接注入:通过 .WithReference() 自动将连接字符串或客户端实例注入到目标服务,避免硬编码。
- 开箱即用的可观测性:所有数据库操作(查询、命令)自动记录为 OpenTelemetry Span,可在 Dashboard 中查看耗时、错误率等指标。
4.2 PostgreSQL 集成(推荐用于云原生)
PostgreSQL 是 Aspire 默认推荐的关系型数据库,因其开源、稳定、功能丰富(JSONB、全文搜索、GIS 等)。
4.2.1 在 App Host 中声明 PostgreSQL
// ECommerce.AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);
// 添加 PostgreSQL 实例(本地由 Docker 启动)
var postgres = builder.AddPostgres("ecommerce-db")
.WithDataVolume("pgdata") // 持久化数据卷
.WithPgAdmin() // 可选:附带 pgAdmin 管理界面
.WithPassword("SecurePass123!");
// 注入到订单服务
builder.AddProject<Projects.OrderService>("orderservice")
.WithReference(postgres);
✅ .WithDataVolume() 确保容器重启后数据不丢失。
✅ .WithPgAdmin() 启动 pgAdmin 容器,访问地址由 Dashboard 提供。
4.2.2 在服务中使用 EF Core 10
首先安装包:
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
定义 DbContext:
// OrderContext.cs
public class OrderContext : DbContext
{
public OrderContext(DbContextOptions<OrderContext> options) : base(options) { }
public DbSet<Order> Orders => Set<Order>();
public DbSet<OrderItem> OrderItems => Set<OrderItem>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>(entity =>
{
entity.Property(o => o.CreatedAt).HasDefaultValueSql("NOW()");
entity.OwnsOne(o => o.ShippingAddress); // EF Core 10 支持更灵活的 Owned Types
});
}
}
在 OrderService 的 Program.cs 中注册:
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// 关键:自动注入连接字符串并配置 DbContext
builder.AddNpgsqlDbContext<OrderContext>("ecommerce-db");
var app = builder.Build();
app.MapDefaultHealthChecks();
// 启用自动迁移(仅开发环境!)
if (app.Environment.IsDevelopment())
{
using var scope = app.Services.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<OrderContext>();
context.Database.Migrate(); // EF Core 迁移
}
app.Run();
🔑 AddNpgsqlDbContext<T>("ecommerce-db") 是 Aspire 扩展方法,自动从 App Host 获取连接字符串并配置连接池。
4.3 SQL Server 集成
对于企业级应用,SQL Server 仍是重要选择。
4.3.1 声明 SQL Server 资源
var sqlserver = builder.AddSqlServer("inventory-db")
.WithDataVolume()
.WithSaPassword("YourStrong@Passw0rd");
⚠️ 注意:SQL Server 容器镜像较大(约 1.5GB),首次启动较慢。
4.3.2 使用 EF Core 连接
builder.AddSqlServerDbContext<InventoryContext>("inventory-db");
EF Core 配置类似 PostgreSQL,只需更换提供程序:
// 安装包
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
// DbContext 无需修改,仅注册方式不同
4.4 MongoDB 集成(文档数据库)
适用于灵活 Schema、高写入吞吐场景(如日志、用户行为分析)。
4.4.1 声明 MongoDB 资源
var mongo = builder.AddMongoDB("analytics-db")
.WithDataVolume();
4.4.2 在服务中使用 MongoDB.Driver
安装驱动:
dotnet add package MongoDB.Driver
注册客户端:
// Program.cs
builder.AddMongoDBClient("analytics-db"); // 注入 IMongoClient
// 在服务中使用
public class UserBehaviorService
{
private readonly IMongoCollection<UserEvent> _events;
public UserBehaviorService(IMongoClient mongoClient)
{
var database = mongoClient.GetDatabase("analytics");
_events = database.GetCollection<UserEvent>("userevents");
}
public async Task LogEvent(UserEvent evt)
{
await _events.InsertOneAsync(evt);
}
}
✅ Aspire 自动处理连接字符串、认证、TLS(生产环境)。
4.5 Entity Framework Core 10 新特性实战
.NET 10 搭配 EF Core 10 带来多项改进:
4.5.1 编译时查询验证(Compile-time Query Validation)
在 csproj 中启用:
<PropertyGroup>
<EnableEFCorePreviewFeatures>true</EnableEFCorePreviewFeatures>
<EFCORE_COMPILE_TIME_QUERY_VALIDATION>true</EFCORE_COMPILE_TIME_QUERY_VALIDATION>
</PropertyGroup>
现在,无效的 LINQ 查询会在 编译时报错,而非运行时!
// 以前:运行时抛异常
var orders = context.Orders.Where(o => o.NonExistentProperty == "test");
// 现在:编译失败,IDE 立即提示
4.5.2 更高效的批量操作(Bulk Updates/Deletes)
EF Core 10 原生支持批量更新,无需第三方库:
// 批量更新:所有未发货订单标记为延迟
await context.Orders
.Where(o => o.Status == OrderStatus.Pending && o.CreatedAt < DateTime.UtcNow.AddDays(-7))
.ExecuteUpdateAsync(setters => setters
.SetProperty(o => o.Status, OrderStatus.Delayed)
.SetProperty(o => o.UpdatedAt, DateTime.UtcNow));
💡 性能提升:直接生成 UPDATE ... WHERE SQL,避免加载实体到内存。
4.5.3 JSON 列映射增强(PostgreSQL / SQL Server 2022+)
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
// 映射为 JSON 列
[Column(TypeName = "jsonb")] // PostgreSQL
public ProductMetadata Metadata { get; set; } = new();
}
public class ProductMetadata
{
public string Brand { get; set; }
public List<string> Tags { get; set; } = [];
}
查询 JSON 字段:
var branded = context.Products
.Where(p => p.Metadata.Brand == "Nike")
.ToList();
EF Core 10 自动生成 ->> 或 JSON_VALUE 查询。
4.6 数据库迁移(Migrations)管理策略
4.6.1 开发环境:自动迁移
如前所述,在 Program.cs 中调用 context.Database.Migrate() 适用于快速迭代。
4.6.2 测试环境:迁移脚本
生成 SQL 脚本用于 CI/CD:
dotnet ef migrations script --output ./migrations.sql
4.6.3 生产环境:手动审批 + 回滚计划
- 禁止自动迁移!
- 使用 Aspire 的部署清单(Deployment Manifest)配合 Azure DevOps 或 GitHub Actions。
- 每次迁移前备份数据库。
- 编写对应的回滚迁移(Down 方法)。
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "NewFeatureTable");
}
4.7 连接池与性能优化
4.7.1 Npgsql 连接池配置(PostgreSQL)
Aspire 默认使用合理的连接池设置,但可覆盖:
builder.AddNpgsqlDbContext<OrderContext>("ecommerce-db", settings =>
{
settings.ConnectionStringBuilder.MaxPoolSize = 100;
settings.ConnectionStringBuilder.Timeout = 30;
});
4.7.2 监控慢查询
在 Aspire Dashboard 的 Metrics 标签页中,可查看:
- db.client.calls.duration:数据库调用耗时分布
- db.client.connections.usage:连接池使用率
点击具体 Span 可看到完整 SQL 语句(已脱敏)。
4.8 多数据库场景(CQRS 模式)
某些系统需读写分离或混合数据库。
示例:订单写入 PostgreSQL,分析数据写入 MongoDB。
// App Host
var postgres = builder.AddPostgres("order-db");
var mongo = builder.AddMongoDB("analytics-db");
builder.AddProject<Projects.OrderService>("orderservice")
.WithReference(postgres)
.WithReference(mongo);
在服务中分别注入:
builder.AddNpgsqlDbContext<OrderWriteContext>("order-db");
builder.AddMongoDBClient("analytics-db");
实现 CQRS:
- Command:写入 OrderWriteContext
- Event Handler:发布事件后,写入 MongoDB 用于分析
4.9 本章小结
本章全面覆盖了 Aspire 中的数据持久化方案:
- PostgreSQL / SQL Server / MongoDB 的声明式集成;
- EF Core 10 的编译时验证、批量操作、JSON 支持;
- 连接管理、迁移策略、性能监控的最佳实践;
- 多数据库架构的实现思路。
Aspire 让数据库不再是“基础设施负担”,而是 可编程、可观测、可维护 的应用组件。
第五章:Aspire 的可观测性体系(Observability)
在分布式系统中,“看不见”比“出错”更可怕。当一个用户请求穿越多个微服务、数据库和消息队列时,如何快速定位性能瓶颈或故障点?答案是:可观测性(Observability)。
.NET Aspire 内置了基于 OpenTelemetry 的端到端可观测性栈,无需额外配置即可获得:
- 日志(Logs):结构化记录事件;
- 指标(Metrics):量化系统状态(如请求率、错误率、延迟);
- 追踪(Traces):可视化跨服务调用链。
本章将深入讲解 Aspire 如何实现这三大支柱,并展示如何扩展、导出数据到外部监控系统。
5.1 OpenTelemetry 与 Aspire 的集成架构
Aspire 的可观测性基于以下组件:
| 组件 |
作用 |
默认启用 |
OpenTelemetry SDK |
.NET 官方遥测库 |
✅ |
OTLP Exporter |
将遥测数据发送到 Collector |
✅(本地 Dashboard) |
Aspire Dashboard |
本地开发用的聚合视图 |
✅ |
ILogger + ActivitySource |
日志与追踪的编程接口 |
✅ |
📦 所有功能通过 builder.AddServiceDefaults() 自动启用。
5.1.1 Service Defaults 中的遥测配置
查看 MyApp.ServiceDefaults/Extensions.cs:
public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
{
// 启用 OpenTelemetry
builder.ConfigureOpenTelemetry();
// 健康检查、服务发现等
builder.AddHealthChecks();
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.AddRuntimeInstrumentation() // .NET 运行时指标
.AddBuiltInMeters(); // HTTP、gRPC、DB 等
})
.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation() // ASP.NET Core 追踪
.AddGrpcClientInstrumentation() // gRPC 客户端
.AddNpgsql() // PostgreSQL
.AddRedis() // Redis
.AddSource("MyApp.*"); // 自定义 ActivitySource
});
// 若在 App Host 中运行,自动发送到 Dashboard
if (builder.Environment.IsDevelopment())
{
builder.Services.ConfigureOpenTelemetryExporter();
}
return builder;
}
✅ 开发者只需调用 AddServiceDefaults(),即可获得完整遥测能力。
5.2 日志(Logs):结构化与上下文关联
5.2.1 使用 ILogger 记录结构化日志
public class OrderService
{
private readonly ILogger<OrderService> _logger;
public OrderService(ILogger<OrderService> logger)
{
_logger = logger;
}
public async Task ProcessOrderAsync(string orderId)
{
using (_logger.BeginScope("OrderId: {OrderId}", orderId))
{
_logger.LogInformation("开始处理订单");
try
{
// 业务逻辑...
_logger.LogInformation("订单处理成功");
}
catch (Exception ex)
{
_logger.LogError(ex, "订单处理失败");
throw;
}
}
}
}
5.2.2 日志特性
- 结构化:
OrderId: "ORD-123" 被解析为字段,非纯文本;
- 自动关联 Trace ID:每条日志包含
trace_id 和 span_id;
- 级别过滤:可在 Dashboard 中按 Info/Warning/Error 筛选。
5.2.3 在 Aspire Dashboard 查看日志
- 打开 http://localhost:17100
- 点击左侧 Logs
- 选择服务(如 orderservice)
- 实时流式显示,支持关键词搜索、时间范围筛选
💡 提示:点击任意日志行,可跳转到对应的 Trace,实现“日志 → 追踪”联动。
5.3 指标(Metrics):量化系统健康度
Aspire 自动收集以下指标:
| 类别 |
示例指标 |
| HTTP |
http.server.request.duration, http.server.active_requests |
| gRPC |
grpc.server.call.duration |
| 数据库 |
db.client.calls.duration, db.client.connections.usage |
| .NET 运行时 |
process.cpu.time, gc.heap.size |
| 自定义 |
开发者定义的业务指标 |
5.3.1 查看内置指标
在 Dashboard 中:
- 进入 Metrics 标签页
- 选择服务 → 选择指标名称 → 查看时间序列图表
例如:http.server.request.duration 显示 P50/P90/P99 延迟。
5.3.2 定义自定义指标(.NET 10 新 API)
使用 Meter 和 Counter/Histogram:
// 定义 Meter(全局单例)
private static readonly Meter s_meter = new("MyApp.OrderService", "1.0");
private static readonly Histogram<double> s_orderProcessingTime =
s_meter.CreateHistogram<double>("order.processing.time", "ms", "订单处理耗时");
public async Task ProcessOrderAsync(string orderId)
{
var startTime = Stopwatch.GetTimestamp();
try
{
// 处理逻辑...
}
finally
{
var elapsedMs = (Stopwatch.GetElapsedTime(startTime).TotalMilliseconds);
s_orderProcessingTime.Record(elapsedMs, KeyValuePair.Create("status", "success"));
}
}
📊 该指标会自动出现在 Dashboard 的 Metrics 列表中,并可设置告警阈值(未来版本支持)。
5.4 追踪(Traces):端到端调用链可视化
这是 Aspire 最强大的功能之一。
5.4.1 自动追踪覆盖范围
| 组件 |
是否自动追踪 |
| ASP.NET Core HTTP 请求 |
✅ |
| HttpClient 调用 |
✅(需使用命名客户端) |
| gRPC 调用 |
✅ |
| EF Core / Npgsql 查询 |
✅ |
| Redis 命令 |
✅ |
| RabbitMQ 发布/消费 |
❌(需手动埋点) |
5.4.2 查看 Trace 链路
在 Dashboard 中:
- 进入 Traces 标签页
- 点击任意 Trace ID
- 查看瀑布图:每个 Span 的服务、操作、耗时、标签
例如:
WebFrontend: GET /orders
└── OrderService: GET http://orderservice/api/orders
├── PostgreSQL: SELECT * FROM Orders
└── Redis: GET order:cache:123
每个 Span 包含:
- 开始时间、持续时间
- 属性(如 SQL 语句、HTTP 方法)
- 异常信息(如有)
5.4.3 手动创建自定义 Span
对于未自动覆盖的操作(如业务逻辑块):
using var activity = MyActivitySource.StartActivity("ValidateInventory");
try
{
// 库存校验逻辑...
activity?.SetTag("product.id", productId);
activity?.SetTag("stock.available", available);
}
catch (Exception ex)
{
activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
throw;
}
需先定义 ActivitySource:
public static class MyActivitySource
{
public static readonly ActivitySource Instance =
new("MyApp.OrderService", "1.0");
}
并在 ConfigureOpenTelemetry 中注册:
tracing.AddSource("MyApp.OrderService");
5.5 将遥测数据导出到外部系统
本地 Dashboard 仅用于开发。生产环境需对接专业监控平台。
5.5.1 导出到 Prometheus + Grafana
Aspire 支持 Prometheus 抓取端点:
// 在服务的 Program.cs 中(生产环境)
if (!app.Environment.IsDevelopment())
{
app.MapPrometheusScrapingEndpoint(); // /metrics
}
然后在 Prometheus 配置中添加目标:
scrape_configs:
- job_name: 'orderservice'
static_configs:
- targets: ['orderservice:8080']
Grafana 导入 .NET 官方仪表盘模板,即可可视化指标。
5.5.2 导出到 Azure Monitor
在 App Host 或服务中配置 OTLP 导出器:
// 仅生产环境
if (!builder.Environment.IsDevelopment())
{
builder.Services.AddOpenTelemetry()
.UseAzureMonitor(); // 需安装 Azure.Monitor.OpenTelemetry.AspNetCore
}
自动将 Logs/Metrics/Traces 发送到 Application Insights。
5.5.3 自定义 OTLP Collector
若使用私有 Collector(如 Jaeger、Tempo):
builder.Services.AddOpenTelemetry()
.ConfigureResource(resource => resource.AddService(builder.Environment.ApplicationName))
.UseOtlpExporter(OtlpExportProtocol.HttpProtobuf, "http://otel-collector:4318");
5.6 健康检查(Health Checks)集成
Aspire 将健康检查纳入可观测体系:
builder.AddServiceDefaults(); // 已包含 AddHealthChecks()
// 可额外添加自定义检查
builder.Services.AddHealthChecks()
.AddNpgSql(connectionString: "from reference")
.AddRedis(redisConnectionString: "from reference");
访问 /health 端点返回:
{
"status": "Healthy",
"results": {
"self": { "status": "Healthy" },
"postgres": { "status": "Healthy" },
"redis": { "status": "Healthy" }
}
}
Dashboard 会定期轮询该端点,并在资源拓扑图中显示服务健康状态(绿色/红色)。
5.7 本章小结
本章全面解析了 Aspire 的可观测性体系:
- 开箱即用的日志、指标、追踪三大支柱;
- 自动埋点覆盖 HTTP、gRPC、数据库等核心组件;
- 结构化日志与 Trace ID 关联,实现快速根因分析;
- 自定义指标与 Span 满足业务监控需求;
- 无缝导出到 Prometheus、Azure Monitor 等生产级系统;
- 健康检查集成,保障服务可用性。
借助 Aspire,开发者不再需要“盲调”分布式系统。
第六章:Aspire 的部署与 DevOps 实践
开发只是起点,可靠、安全、自动化的部署 才是云原生应用落地的关键。.NET Aspire 不仅优化了本地开发体验,还为生产环境提供了从 Docker Compose 到 Kubernetes 再到托管平台(如 Azure Container Apps) 的全栈部署能力。
本章将系统讲解:
- Aspire 的部署模型与资源抽象
- 生成 Docker Compose 文件并本地验证
- 部署到 Kubernetes(含 Helm 支持)
- 一键发布到 Azure Container Apps
- CI/CD 流水线设计(GitHub Actions / Azure DevOps)
- 配置管理与密钥安全(Azure Key Vault 集成)
6.1 Aspire 的部署架构理念
Aspire 采用 “一次定义,多端部署” 的策略:
- App Host 项目是唯一的部署蓝图(C# 代码即基础设施);
- 通过 dotnet aspire CLI 或 MSBuild 目标,可生成不同目标平台的部署工件;
- 所有依赖(数据库、缓存、消息队列)在生产环境中不再由 Aspire 启动,而是引用外部服务(如 Azure Database for PostgreSQL)。
✅ 核心原则:开发用容器,生产用托管服务。
6.2 生成并运行 Docker Compose(适用于测试/演示)
虽然不推荐用于生产,但 Docker Compose 是验证部署逻辑的快速方式。
6.2.1 生成 Compose 文件
在项目根目录执行:
dotnet build -t:PublishAsDockerCompose ECommercePlatform.AppHost
生成文件位于:
ECommercePlatform.AppHost/bin/Debug/net10.0/publish/docker-compose.yml
6.2.2 查看生成的 docker-compose.yml(片段)
services:
orderservice:
image: orderservice:1.0
ports:
- "8080"
depends_on:
- postgresdb
- redis
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
- ConnectionStrings__postgresdb=Host=postgresdb;...
postgresdb:
image: postgres:16
environment:
POSTGRES_PASSWORD: SecurePass123!
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
🔍 注意:连接字符串、环境变量均由 Aspire 自动注入。
6.2.3 运行 Compose 环境
cd ECommercePlatform.AppHost/bin/Debug/net10.0/publish
docker compose up -d
访问服务(端口由 Docker 动态映射,可通过 docker compose ps 查看)。
⚠️ 局限:Compose 不支持自动扩缩容、服务网格、高级网络策略,仅适合非关键场景。
6.3 部署到 Kubernetes
Aspire 支持生成标准 Kubernetes 清单(YAML)或 Helm Chart。
6.3.1 生成 Kubernetes 清单
dotnet build -t:PublishToKubernetes ECommercePlatform.AppHost
输出目录:
ECommercePlatform.AppHost/bin/Debug/net10.0/publish/kubernetes/
├── deployment.yaml
├── service.yaml
├── configmap.yaml
└── secret.yaml(若配置了密钥)
6.3.2 关键资源配置示例
Deployment (orderservice):
apiVersion: apps/v1
kind: Deployment
metadata:
name: orderservice
spec:
replicas: 2
template:
spec:
containers:
- name: orderservice
image: myacr.azurecr.io/orderservice:1.0
env:
- name: ConnectionStrings__ecommerce_db
valueFrom:
secretKeyRef:
name: ecommerce-db-secret
key: connectionString
ports:
- containerPort: 8080
Service:
apiVersion: v1
kind: Service
metadata:
name: orderservice
spec:
selector:
app: orderservice
ports:
- protocol: TCP
port: 80
targetPort: 8080
6.3.3 应用到集群
kubectl apply -f kubernetes/
✅ 优势:完全兼容标准 K8s 生态,可配合 Istio、Prometheus Operator 等使用。
6.4 一键部署到 Azure Container Apps(推荐生产方案)
Azure Container Apps(ACA)是微软提供的 全托管无服务器容器平台,完美契合 Aspire 的设计理念。
6.4.1 前提条件
- Azure 订阅
- 已安装 Azure CLI (az login)
- 已创建 Resource Group 和 Container Apps Environment
6.4.2 使用 Aspire CLI 一键部署
# 安装 Aspire Azure 扩展(若未安装)
dotnet workload install aspire-azure
# 部署整个应用拓扑到 Azure
dotnet aspire deploy --environment MyAcaEnv --resource-group MyResourceGroup
Aspire 会自动:
- 构建所有服务镜像并推送到 ACR(Azure Container Registry);
- 在 ACA 中创建应用实例;
- 创建 Azure Database for PostgreSQL、Azure Cache for Redis 等托管资源;
- 注入连接字符串和密钥;
- 配置 Ingress、健康检查、自动扩缩容。
🌟 无需编写一行 ARM/Bicep/Terraform!
6.4.3 自定义 Azure 资源(高级)
在 App Host 中显式指定使用 Azure 托管服务:
var builder = DistributedApplication.CreateBuilder(args);
// 使用 Azure Database for PostgreSQL
var postgres = builder.AddAzurePostgres("ecommerce-db")
.WithAdministratorLogin("adminuser")
.WithAdministratorPassword("SecurePass123!");
// 使用 Azure Redis Cache
var redis = builder.AddAzureRedis("cache");
// 服务引用不变
builder.AddProject<Projects.OrderService>("orderservice")
.WithReference(postgres)
.WithReference(redis);
部署时,Aspire 将跳过本地容器,直接创建 Azure PaaS 资源。
6.5 CI/CD 流水线设计
6.5.1 GitHub Actions 示例
.github/workflows/deploy.yml:
name: Deploy to Azure Container Apps
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET 10
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Install Aspire workload
run: dotnet workload install aspire-azure
- name: Login to Azure
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Deploy Aspire app
run: |
dotnet aspire deploy \
--environment ${{ vars.ACA_ENV }} \
--resource-group ${{ vars.RG_NAME }}
🔐 安全提示:AZURE_CREDENTIALS 应为最小权限的服务主体(Service Principal)。
6.5.2 Azure DevOps Pipeline
使用 DotNetCoreCLI@2 任务 + AzureCLI@2:
steps:
- task: DotNetCoreCLI@2
inputs:
command: 'custom'
custom: 'aspire'
arguments: 'deploy --environment $(acaEnv) --resource-group $(rgName)'
6.6 配置管理与密钥安全
6.6.1 开发 vs 生产配置分离
- 开发:App Host 直接提供连接字符串(明文,仅本地);
- 生产:使用 Azure Key Vault / AWS Secrets Manager。
6.6.2 集成 Azure Key Vault
在服务中启用:
// Program.cs
if (!app.Environment.IsDevelopment())
{
var keyVaultUri = builder.Configuration["KeyVault:Uri"];
builder.Configuration.AddAzureKeyVault(
new Uri(keyVaultUri),
new DefaultAzureCredential());
}
在 App Host 中引用密钥:
// 不再硬编码密码
var postgres = builder.AddAzurePostgres("ecommerce-db");
// 密码存储在 Key Vault,名为 "PostgresAdminPassword"
builder.AddAzureKeyVault("mykeyvault")
.WithReference(postgres); // Aspire 自动关联
部署时,Aspire 会:
- 创建 Key Vault;
- 生成强密码并存入;
- 授予服务 MSI(托管身份)读取权限。
✅ 实现“零密钥代码化”。
6.7 本章小结
本章全面覆盖了 Aspire 的部署与 DevOps 实践:
- Docker Compose:快速验证;
- Kubernetes:标准云原生部署;
- Azure Container Apps:推荐的全托管方案,一键部署;
- CI/CD 集成:GitHub Actions / Azure DevOps 自动化流水线;
- 安全配置:Key Vault 集成,实现密钥零暴露。
Aspire 让开发者从“部署焦虑”中解放,真正实现 “开发即部署” 的无缝体验。
第七章:Aspire 的安全性与认证授权体系
在微服务架构中,安全不再是边界防御,而是贯穿每个服务的内生能力。.NET Aspire 基于 .NET 10 的现代安全模型,为开发者提供了一套端到端的身份验证(Authentication)、授权(Authorization)、传输安全和防护机制,同时保持开发体验的简洁性。
本章将深入讲解:
- 身份认证集成(JWT、OpenID Connect、Azure AD)
- 服务间安全调用(mTLS、令牌传递)
- API 网关模式与统一入口控制
- 安全头、CORS、速率限制等防护策略
- 零信任架构在 Aspire 中的实践
7.1 认证与授权基础:从单体到分布式
传统单体应用通常依赖 Cookie + Session,但在微服务中:
- 前端 → 后端:使用 Bearer Token(如 JWT);
- 服务 → 服务:使用客户端凭证(Client Credentials)或令牌中继(Token Relay);
- 所有通信:必须通过 HTTPS(生产环境强制)。
Aspire 默认不启用认证,但提供了无缝集成路径。
7.2 集成 OpenID Connect(OIDC)与 Azure AD
7.2.1 前端 Web 应用登录(Blazor Server / MVC)
以 Blazor Server 为例,在 WebFrontend 项目中:
dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect
dotnet add package Microsoft.Identity.Web
Program.cs 配置:
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// 启用 OIDC(以 Azure AD 为例)
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication(); // 必须在 UseAuthorization 之前
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");
app.Run();
appsettings.json(开发时可放本地,生产用 Key Vault):
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "yourdomain.onmicrosoft.com",
"TenantId": "your-tenant-id",
"ClientId": "your-web-client-id",
"CallbackPath": "/signin-oidc"
}
}
✅ 用户登录后,身份信息自动注入 HttpContext.User。
7.3 服务间安全调用:令牌中继(Token Relay)
当 WebFrontend 调用 OrderService 时,需将用户令牌传递过去,实现 委托授权。
7.3.1 在 WebFrontend 中配置 Token Relay
// 注册命名 HttpClient,并启用令牌中继
builder.Services.AddHttpClient("OrderApiClient", client =>
{
client.BaseAddress = new Uri("http://orderservice");
}).AddHttpMessageHandler(sp =>
{
var handler = sp.GetRequiredService<AuthorizationMessageHandler>()
.ConfigureHandler(
authorizedUrls: ["http://orderservice"],
scopes: ["api://order-service/access_as_user"] // 受保护 API 的 scope
);
return handler;
});
🔑 AuthorizationMessageHandler 是 Microsoft.Identity.Web 提供的组件,自动附加访问令牌。
7.3.2 在 OrderService 中验证令牌
OrderService/Program.cs:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/orders", (ClaimsPrincipal user) =>
{
var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
return Results.Ok($"Orders for user {userId}");
});
appsettings.json(OrderService):
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"Audience": "api://order-service" // 必须与 Azure AD 中“公开 API”配置一致
}
}
✅ 实现:用户登录 Web → Web 获取用户令牌 → 调用 OrderService 时附带该令牌 → OrderService 验证并识别用户。
7.4 服务间机器对机器调用:客户端凭证流(Client Credentials)
对于后台任务(如 InventoryWorker 消费 RabbitMQ),无需用户上下文,使用 服务主体(Service Principal)。
7.4.1 在 Azure AD 中注册应用(无用户交互)
- 创建两个应用注册:
- InventoryWorker(客户端)
- ProductCatalogApi(资源服务器)
- 在 ProductCatalogApi 中暴露 API 权限(如 catalog.read)
- 授予 InventoryWorker 该权限
7.4.2 在 InventoryWorker 中获取令牌
// 使用 Microsoft.Identity.Client (MSAL)
var app = ConfidentialClientApplicationBuilder
.Create("inventory-worker-client-id")
.WithClientSecret("client-secret-from-keyvault")
.WithAuthority(AzureCloudInstance.AzurePublic, "tenant-id")
.Build();
var result = await app.AcquireTokenForClient(new[] { "api://product-catalog/catalog.read" })
.ExecuteAsync();
var token = result.AccessToken;
🔐 生产环境中,client-secret 应从 Azure Key Vault 读取,或使用托管身份(Managed Identity)。
7.4.3 在 ProductCatalogApi 中验证范围(Scope)
services.AddAuthorization(options =>
{
options.AddPolicy("CatalogRead", policy =>
policy.RequireClaim("scp", "catalog.read"));
});
app.MapGet("/products", [Authorize("CatalogRead")] () => ...);
7.5 API 网关模式(可选但推荐)
虽然 Aspire 支持服务直连,但在生产环境中,建议引入 API 网关 作为统一入口,集中处理:
7.5.1 使用 YARP(微软开源反向代理)
在 App Host 中添加网关项目:
dotnet new web -o ApiGateway
安装 YARP:
dotnet add package Yarp.ReverseProxy
Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
// 全局认证
app.UseAuthentication();
app.UseAuthorization();
app.MapReverseProxy();
app.Run();
appsettings.json:
{
"ReverseProxy": {
"Routes": {
"order-route": {
"ClusterId": "orderservice",
"Match": {
"Path": "/api/orders/{**catch-all}"
}
}
},
"Clusters": {
"orderservice": {
"Destinations": {
"orderservice/destination": {
"Address": "http://orderservice:8080"
}
}
}
}
}
}
在 App Host 中引用:
var gateway = builder.AddProject<Projects.ApiGateway>("apigateway")
.WithReference(orderService)
.WithHttpsEndpoint(); // 对外暴露 HTTPS
✅ 所有外部请求先经过网关,内部服务可简化安全逻辑。
7.6 安全防护策略
7.6.1 强制 HTTPS(生产环境)
在服务中:
if (!app.Environment.IsDevelopment())
{
app.UseHttpsRedirection();
app.UseHsts(); // HTTP Strict Transport Security
}
在 Azure Container Apps 中,HTTPS 由平台自动终止。
7.6.2 CORS 策略
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowFrontend", policy =>
{
policy.WithOrigins("https://mywebapp.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
app.UseCors("AllowFrontend");
7.6.3 速率限制(Rate Limiting)
.NET 7+ 内置速率限制中间件:
builder.Services.AddRateLimiter(options =>
{
options.AddPolicy("PerUser", context =>
{
var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
return RateLimitPartition.GetFixedWindowLimiter(userId, _ => new FixedWindowRateLimiterOptions
{
PermitLimit = 100,
Window = TimeSpan.FromMinutes(1)
});
});
});
app.UseRateLimiter();
7.7 零信任架构(Zero Trust)实践
零信任核心原则:永不信任,始终验证。
在 Aspire 中实现:
- 所有服务默认拒绝外部访问(仅 App Host 或网关可路由);
- 服务间通信强制认证(即使在同一 VPC);
- 最小权限原则:每个服务仅拥有必要权限;
- 持续监控:异常登录、高频失败请求触发告警。
Aspire 通过以下方式支持:
- 自动网络隔离(Kubernetes NetworkPolicy / ACA Ingress Restrictions)
- 托管身份(Managed Identity)替代密钥
- OpenTelemetry 记录所有认证事件
7.8 本章小结
本章系统构建了 Aspire 的安全体系:
- 用户认证:OIDC + Azure AD 集成;
- 服务间安全:令牌中继(用户上下文)与客户端凭证(机器上下文);
- API 网关:YARP 实现统一入口控制;
- 防护策略:HTTPS、CORS、速率限制;
- 零信任:最小权限、持续验证、可观测审计。
第八章:Aspire 的测试策略与质量保障
在云原生微服务架构中,“能跑”不等于“可靠”。一个由多个服务、数据库、消息队列组成的分布式系统,其复杂性远超单体应用。因此,必须建立 多层次、自动化、可重复 的测试体系,覆盖从代码逻辑到端到端业务流程的全链路。
.NET Aspire 不仅简化了开发和部署,也为测试提供了强大支持:
- 本地集成测试:一键启动完整依赖栈;
- 容器化测试环境:与生产环境高度一致;
- 服务模拟与契约测试:解耦团队协作;
- 混沌工程集成:验证系统韧性。
本章将系统讲解如何在 Aspire 项目中实施高质量测试实践。
8.1 测试金字塔在 Aspire 中的重构
传统测试金字塔(单元 > 集成 > E2E)在微服务中需调整:
┌───────────────────────┐
│ 端到端业务流测试 │ ← 覆盖跨服务关键路径(少量)
└──────────┬────────────┘
│
┌──────────▼────────────┐
│ 服务级集成测试 │ ← 模拟依赖或使用真实容器(中量)
└──────────┬────────────┘
│
┌──────────▼────────────┐
│ 单元测试 + 契约测试 │ ← 快速反馈,高覆盖率(大量)
└───────────────────────┘
Aspire 的核心优势在于:让集成测试像单元测试一样简单。
8.2 单元测试:聚焦业务逻辑
单元测试应 隔离外部依赖(数据库、HTTP 客户端等),使用 Mock 或 Fake。
8.2.1 示例:测试订单创建逻辑
// OrderService.Tests/OrderServiceTests.cs
public class OrderServiceTests
{
[Fact]
public void CreateOrder_WithValidItems_ShouldSucceed()
{
// Arrange
var mockInventoryClient = new Mock<IInventoryClient>();
mockInventoryClient.Setup(c => c.CheckStockAsync(It.IsAny<string>()))
.ReturnsAsync(true);
var service = new OrderApplicationService(mockInventoryClient.Object);
// Act
var result = await service.CreateOrderAsync(new CreateOrderDto { Items = [...] });
// Assert
Assert.NotNull(result.OrderId);
Assert.Equal(OrderStatus.Pending, result.Status);
}
}
✅ 使用 Moq 或 NSubstitute 模拟接口,确保测试快速、稳定。
8.3 集成测试:Aspire 的杀手级特性
Aspire 提供 TestProject 和 DistributedApplicationTesting 包,允许在测试中 启动真实服务及其依赖(如 PostgreSQL、Redis),但以轻量、隔离的方式运行。
8.3.1 启用集成测试支持
在测试项目中安装:
dotnet add package Microsoft.Extensions.Hosting
dotnet add package Aspire.Hosting.Testing
8.3.2 编写集成测试
// OrderService.IntegrationTests/OrderApiTests.cs
public class OrderApiTests : IClassFixture<DistributedApplicationFactory<ECommerce.AppHost.Program>>
{
private readonly DistributedApplication _app;
private readonly HttpClient _httpClient;
public OrderApiTests(DistributedApplicationFactory<ECommerce.AppHost.Program> factory)
{
_app = factory.Create();
_httpClient = _app.CreateHttpClient("orderservice"); // 自动解析服务地址
}
[Fact]
public async Task CreateOrder_EndToEnd_ShouldPersistInDatabase()
{
// Arrange
var orderDto = new { CustomerId = "user123", Items = new[] { new { ProductId = "prod1", Quantity = 2 } } };
// Act
var response = await _httpClient.PostAsJsonAsync("/api/orders", orderDto);
// Assert
response.EnsureSuccessStatusCode();
var orderId = await response.Content.ReadFromJsonAsync<string>();
// 可选:直接查询数据库验证(通过另一个 HttpClient 或 EF Core)
var dbResponse = await _httpClient.GetAsync($"/api/orders/{orderId}");
var order = await dbResponse.Content.ReadFromJsonAsync<OrderDto>();
Assert.Equal("user123", order.CustomerId);
}
public void Dispose() => _app.Dispose();
}
8.3.3 关键机制说明
DistributedApplicationFactory<T>:启动完整的 App Host(含所有服务和依赖);
_app.CreateHttpClient("orderservice"):自动获取服务的 HTTP 端点(无需硬编码 localhost:port);
- 所有资源在测试结束后自动清理(容器停止、卷删除);
- 支持并行测试(每个测试获得独立实例)。
🚀 这是 Aspire 最强大的测试能力:无需修改代码,即可对整个拓扑进行集成测试。
8.4 端到端(E2E)测试:验证用户旅程
E2E 测试模拟真实用户操作,通常从前端开始,贯穿多个后端服务。
8.4.1 使用 Playwright + Aspire
Playwright 是微软开源的浏览器自动化工具,支持 Chromium、Firefox、WebKit。
安装:
dotnet new install Microsoft.Playwright.CLI
dotnet tool install --global Microsoft.Playwright.CLI
playwright install
测试示例:
// E2eTests/CheckoutFlowTests.cs
[Collection("Aspire E2E")] // 串行执行(避免资源冲突)
public class CheckoutFlowTests : IAsyncLifetime
{
private DistributedApplication? _app;
private IPage? _page;
private IBrowser? _browser;
public async Task InitializeAsync()
{
_app = await DistributedApplicationFactory.CreateAsync<ECommerce.AppHost.Program>();
var frontendUrl = _app.GetEndpoint("webfrontend", "http");
var browserType = await Playwright.CreateAsync();
_browser = await browserType.Chromium.LaunchAsync();
_page = await _browser.NewPageAsync();
await _page.GotoAsync(frontendUrl.ToString());
}
[Fact]
public async Task UserCanCheckoutOrder()
{
// 模拟用户操作
await _page.ClickAsync("text=Add to Cart");
await _page.ClickAsync("text=Checkout");
await _page.FillAsync("#email", "test@example.com");
await _page.ClickAsync("#submit-order");
// 验证结果
await Expect(_page.Locator("text=Order Confirmed!")).ToBeVisibleAsync();
}
public async Task DisposeAsync()
{
if (_browser != null) await _browser.CloseAsync();
if (_app != null) await _app.DisposeAsync();
}
}
✅ E2E 测试验证的是 真实用户体验,但运行较慢,应聚焦核心业务流(如登录、下单、支付)。
8.5 契约测试(Contract Testing)
当多个团队独立开发服务时,接口变更容易导致集成失败。契约测试通过定义“消费者期望”与“提供者实现”是否匹配,提前发现问题。
8.5.1 使用 Pact(推荐)
Pact 是主流契约测试框架,支持 .NET。
消费者测试(OrderService):
// 定义对 InventoryService 的期望
var mockProvider = new PactBuilder()
.ServiceConsumer("OrderService")
.HasPactWith("InventoryService")
.Build();
mockProvider.UponReceiving("A request for product stock")
.Given("Product prod1 exists")
.WithRequest(HttpMethod.Get, "/stock/prod1")
.WillRespondWith(HttpStatusCode.OK, body: new { InStock = true });
// 在测试中使用 mock URL
var inventoryClient = new InventoryClient(mockProvider.MockServerUri);
await inventoryClient.CheckStockAsync("prod1");
mockProvider.VerifyInteractions(); // 验证调用是否符合契约
提供者验证(InventoryService):
// 使用 Pact 验证实际 API 是否满足契约
[PactVerify] // 自定义属性,运行 Pact 验证器
public void VerifyPacts()
{
var pactVerifier = new PactVerifier("InventoryService");
pactVerifier.ProviderState("Product prod1 exists", setUp: () =>
{
// 准备测试数据
});
pactVerifier.VerifyPactFiles(); // 从 Pact Broker 下载契约
}
🔗 契约文件存储在 Pact Broker(中央仓库),实现消费者与提供者解耦。
8.6 混沌工程:验证系统韧性
“故障是必然的”,混沌工程通过 主动注入故障,验证系统能否优雅降级。
8.6.1 在 Aspire 中模拟故障
利用 Aspire 的可编程性,在测试中动态注入延迟、错误:
// ChaosTest.cs
[Fact]
public async Task OrderService_ShouldHandleInventoryTimeout()
{
var app = await DistributedApplicationFactory.CreateAsync<ECommerce.AppHost.Program>();
// 动态修改 InventoryService 行为:返回 500 或延迟
var inventoryService = app.Services.GetRequiredService<ResourceNotificationService>();
await inventoryService.SendAsync(new SimulateFailure("inventoryservice", statusCode: 500));
var client = app.CreateHttpClient("orderservice");
var response = await client.PostAsJsonAsync("/api/orders", ...);
// 验证降级行为(如返回“稍后重试”)
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
}
💡 实际可通过 Istio 故障注入 或 Chaos Mesh 在 Kubernetes 中实现更真实的混沌实验。
8.7 CI/CD 中的测试流水线
将测试分层集成到流水线:
# GitHub Actions 示例
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Run Unit Tests
run: dotnet test **/*Tests.csproj --filter Category!=Integration
- name: Run Integration Tests
run: dotnet test **/*IntegrationTests.csproj
env:
DOTNET_ASPIRE_TESTING: "true"
- name: Run E2E Tests (on merge to main)
if: github.ref == 'refs/heads/main'
run: dotnet test **/*E2eTests.csproj
⏱️ 建议:
- 单元测试:每次 push 触发;
- 集成测试:PR 合并前触发;
- E2E / 混沌测试:每日夜间或发布前触发。
8.8 本章小结
本章构建了 Aspire 项目的完整质量保障体系:
- 单元测试:快速验证业务逻辑;
- 集成测试:Aspire 原生支持,一键启动真实依赖;
- E2E 测试:Playwright 模拟用户旅程;
- 契约测试:Pact 防止接口不兼容;
- 混沌工程:主动验证系统韧性;
- CI/CD 集成:分层自动化,保障交付质量。
第九章:Aspire 的性能优化与扩展性设计
在云原生时代,“能用”只是起点,“高性能、高可用、可扩展”才是生产级系统的底线。.NET Aspire 不仅简化了架构搭建,还为性能调优和弹性伸缩提供了内建支持。本章将系统讲解如何在 Aspire + .NET 10 项目中实现:
- 高效缓存策略(内存、分布式、响应缓存)
- 异步处理与消息驱动架构(RabbitMQ / Azure Service Bus)
- 水平扩展与负载均衡
- 数据库读写分离与连接池优化
- 负载测试与性能基线建立(k6 / Locust)
- 自动扩缩容(Kubernetes HPA / Azure Container Apps)
9.1 缓存策略:减少重复计算与数据库压力
9.1.1 内存缓存(IMemoryCache)——适用于单实例服务
// Program.cs
builder.Services.AddMemoryCache();
// Service
public class ProductService
{
private readonly IMemoryCache _cache;
public ProductService(IMemoryCache cache) => _cache = cache;
public Product GetProduct(string id)
{
return _cache.GetOrCreate(id, entry =>
{
entry.SlidingExpiration = TimeSpan.FromMinutes(10);
return _dbContext.Products.Find(id); // 实际从 DB 加载
});
}
}
⚠️ 局限:多实例部署时,各实例缓存不一致。
9.1.2 分布式缓存(Redis)——推荐用于生产
Aspire 已集成 Redis,只需引用即可使用。
App Host 中声明 Redis:
var redis = builder.AddRedis("cache")
.WithDataVolume(); // 开发用持久化
服务中注册 IDistributedCache:
// Program.cs
builder.AddRedisClient("cache"); // 注入 IConnectionMultiplexer
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("cache");
});
使用缓存:
public async Task<Product> GetProductAsync(string id)
{
var cached = await _distributedCache.GetStringAsync($"product:{id}");
if (cached != null)
return JsonSerializer.Deserialize<Product>(cached);
var product = await _dbContext.Products.FindAsync(id);
if (product != null)
{
await _distributedCache.SetStringAsync(
$"product:{id}",
JsonSerializer.Serialize(product),
new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
});
}
return product;
}
✅ 所有服务实例共享同一份缓存,保证一致性。
9.1.3 HTTP 响应缓存(Response Caching)
对于公开 API,可启用响应缓存中间件:
// Program.cs
builder.Services.AddResponseCaching();
app.UseResponseCaching();
app.MapGet("/api/products/{id}", [ResponseCache(Duration = 60)] (string id) =>
{
return Results.Ok(new { Id = id, Name = "Cached Product" });
});
🌐 适用于 CDN 或反向代理场景,减少后端请求。
9.2 异步处理与消息队列
同步调用链过长会导致延迟累积和级联故障。关键操作应异步化。
9.2.1 集成 RabbitMQ(开发环境)
App Host:
var rabbit = builder.AddRabbitMQ("eventbus");
发布事件(OrderService):
// 安装包:dotnet add package RabbitMQ.Client
var channel = rabbitConnection.CreateModel();
channel.QueueDeclare("order.created", durable: true, exclusive: false, autoDelete: false);
var body = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(orderEvent));
channel.BasicPublish("", "order.created", basicProperties, body);
消费事件(InventoryWorker):
// Worker 项目
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var channel = _connection.CreateModel();
channel.QueueDeclare("order.created", ...);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += async (model, ea) =>
{
var body = ea.Body.ToArray();
var evt = JsonSerializer.Deserialize<OrderCreatedEvent>(body);
await _inventoryService.ReserveStockAsync(evt.Items);
channel.BasicAck(ea.DeliveryTag, false);
};
channel.BasicConsume("order.created", autoAck: false, consumer);
}
✅ 解耦订单创建与库存扣减,提升系统吞吐量。
9.2.2 生产环境:Azure Service Bus / Amazon SQS
Aspire 支持云原生消息服务:
// 使用 Azure Service Bus
var serviceBus = builder.AddAzureServiceBus("eventbus")
.WithQueue("order-events");
服务中使用 Azure.Messaging.ServiceBus SDK,代码逻辑类似 RabbitMQ,但具备更高 SLA 和死信队列支持。
9.3 水平扩展与负载均衡
9.3.1 Kubernetes 水平 Pod 自动扩缩容(HPA)
Aspire 生成的 Kubernetes 清单默认包含资源请求:
resources:
requests:
memory: "128Mi"
cpu: "100m"
启用 HPA:
kubectl autoscale deployment orderservice --cpu-percent=70 --min=2 --max=10
当 CPU 使用率 >70%,自动增加副本数。
9.3.2 Azure Container Apps 自动扩缩容
ACA 基于 并发请求量 或 CPU/内存使用率 自动扩缩:
- 默认:每实例最多处理 10 个并发请求;
- 当请求数 > 10 × 实例数,自动扩容;
- 空闲时缩容至 0(节省成本)。
无需配置,开箱即用。
9.4 数据库性能优化
9.4.1 连接池调优(Npgsql / SqlClient)
Aspire 默认使用合理连接池设置,但可覆盖:
builder.AddNpgsqlDbContext<OrderContext>("ecommerce-db", settings =>
{
settings.ConnectionStringBuilder.MaxPoolSize = 200; // 默认 100
settings.ConnectionStringBuilder.Timeout = 15; // 连接超时
settings.ConnectionStringBuilder.CommandTimeout = 30; // 命令超时
});
📊 监控指标:db.client.connections.usage(Dashboard 中查看)
9.4.2 读写分离(CQRS 模式)
对于高读负载场景,可分离读写数据库:
// App Host
var writeDb = builder.AddPostgres("order-write-db");
var readDb = builder.AddPostgres("order-read-db");
builder.AddProject<Projects.OrderService>("orderservice")
.WithReference(writeDb)
.WithReference(readDb);
在服务中注册两个 DbContext:
builder.AddNpgsqlDbContext<OrderWriteContext>("order-write-db");
builder.AddNpgsqlDbContext<OrderReadContext>("order-read-db");
// Repository
public class OrderRepository
{
public async Task<Order> GetByIdAsync(string id)
=> await _readContext.Orders.FindAsync(id); // 从只读库读
public async Task SaveAsync(Order order)
{
_writeContext.Orders.Update(order);
await _writeContext.SaveChangesAsync(); // 写入主库
}
}
🔁 主从复制由 PostgreSQL 或 Azure Database 自动处理。
9.5 负载测试:建立性能基线
9.5.1 使用 k6(推荐)
k6 是开发者友好的负载测试工具,脚本用 JavaScript 编写。
安装:
npm install -g k6
测试脚本 order-test.js:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 50 }, // 逐步加压到 50 VUs
{ duration: '1m', target: 50 },
{ duration: '20s', target: 0 }, // 逐步降压
],
};
export default function () {
const res = http.post('http://localhost:5000/api/orders', JSON.stringify({
customerId: 'user123',
items: [{ productId: 'prod1', quantity: 1 }]
}), {
headers: { 'Content-Type': 'application/json' }
});
check(res, {
'status is 201': (r) => r.status === 201,
});
sleep(1);
}
运行测试:
k6 run order-test.js
输出包括:
- RPS(每秒请求数)
- P95/P99 延迟
- 错误率
📈 将结果与 Aspire Dashboard 中的指标对比,定位瓶颈。
9.5.2 使用 Locust(Python)
适合复杂场景(如登录态保持、动态参数)。
from locust import HttpUser, task, between
class OrderUser(HttpUser):
wait_time = between(1, 3)
@task
def create_order(self):
self.client.post("/api/orders", json={
"customerId": "user123",
"items": [{"productId": "prod1", "quantity": 1}]
})
运行:
locust -f order_locust.py
访问 http://localhost:8089 启动 Web UI。
9.6 本章小结
本章全面覆盖了 Aspire 应用的性能与扩展性优化:
- 缓存分层:内存 → Redis → HTTP 响应;
- 异步解耦:RabbitMQ / Service Bus 实现事件驱动;
- 水平扩展:K8s HPA 与 ACA 自动扩缩容;
- 数据库优化:连接池、读写分离;
- 负载测试:k6 / Locust 建立性能基线;
- 可观测联动:通过 Dashboard 验证优化效果。
第十章:Aspire 项目的演进、多环境管理与未来展望
至此,我们已系统掌握了使用 .NET Aspire 构建现代化云原生应用的核心能力:从服务编排、可观测性、安全控制、质量保障到性能优化。然而,真正的工程挑战往往始于项目上线之后——如何持续演进架构?如何管理多套环境?如何控制成本?又如何拥抱未来技术趋势?
本章将聚焦 Aspire 在企业级落地中的关键实践,并展望其发展方向。
10.1 从传统架构迁移到 Aspire
许多团队并非“从零开始”,而是希望将现有 .NET 应用逐步现代化。
10.1.1 迁移策略:绞杀者模式(Strangler Fig Pattern)
🌿 逐步用新服务替换旧功能,而非一次性重写。
步骤:
- 识别边界:将单体应用拆分为业务域(如订单、用户、库存);
- 新建 Aspire 项目:作为新服务宿主;
- 反向代理路由:使用 YARP 或 API 网关,将新路径(如 /api/v2/orders)指向 Aspire 服务,旧路径仍走单体;
- 数据同步:初期可双写数据库,或通过 CDC(变更数据捕获)同步;
- 逐步下线:当新服务覆盖全部功能后,移除旧模块。
10.1.2 示例:迁移订单模块
// App Host 中同时引用旧单体和新服务
var legacyApp = builder.AddContainer("legacy-monolith", "myregistry/legacy:1.0")
.WithHttpEndpoint(port: 80);
var orderService = builder.AddProject<Projects.OrderService>("orderservice");
// YARP 路由配置
builder.AddProject<Projects.ApiGateway>("apigateway")
.WithReference(legacyApp)
.WithReference(orderService);
YARP 配置:
{
"ReverseProxy": {
"Routes": {
"new-orders": {
"Match": { "Path": "/api/v2/orders/{**}" },
"ClusterId": "orderservice"
},
"legacy-fallback": {
"Match": { "Path": "/{**}" },
"ClusterId": "legacy-monolith"
}
}
}
}
✅ 平滑过渡,风险可控。
10.2 多环境管理(Dev / Test / Staging / Prod)
Aspire 通过 C# 代码即基础设施(Infrastructure as Code) 实现环境一致性。
10.2.1 环境差异化配置
在 AppHost 中根据环境切换资源:
var builder = DistributedApplication.CreateBuilder(args);
if (builder.Environment.IsDevelopment())
{
// 开发:使用容器化依赖
var postgres = builder.AddPostgres("ecommerce-db").WithDataVolume();
var redis = builder.AddRedis("cache").WithDataVolume();
}
else
{
// 生产:使用 Azure 托管服务
var postgres = builder.AddAzurePostgres("ecommerce-db");
var redis = builder.AddAzureRedis("cache");
}
builder.AddProject<Projects.OrderService>("orderservice")
.WithReference(postgres)
.WithReference(redis);
10.2.2 使用配置文件覆盖
创建 appsettings.Production.json,并通过部署参数指定:
# 部署到生产
dotnet aspire deploy --environment Production
Aspire 会自动加载对应配置,并注入到各服务中。
10.2.3 环境隔离最佳实践
| 环境 |
资源类型 |
网络隔离 |
数据隔离 |
| Dev |
Docker Compose |
本地网络 |
开发数据库 |
| Test |
Kubernetes Namespace |
NetworkPolicy |
独立 DB 实例 |
| Staging |
ACA Environment |
VNet 集成 |
快照数据 |
| Prod |
ACA / AKS |
私有 Endpoint |
主库 + 备份 |
🔒 关键原则:Prod 环境绝不共享任何资源(包括 Key Vault、DB、消息队列)。
10.3 成本优化策略
云原生 ≠ 高成本。Aspire 帮助你 按需使用、自动伸缩、避免浪费。
10.3.1 开发环境成本控制
- 本地运行:默认不启动未使用的服务(按需启动);
- Docker 资源限制:在 docker-compose.override.yml 中限制 CPU/Memory;
- 自动休眠:开发机闲置时停止容器。
10.3.2 生产环境成本优化
| 措施 |
效果 |
| ACA 缩容至 0 |
无流量时实例数为 0,节省 100% 计算成本 |
| 使用 Spot 实例(K8s) |
批处理任务成本降低 60–90% |
| 连接池复用 |
减少数据库连接数,降低许可费用 |
| CDN + 响应缓存 |
减少后端请求,节省计算资源 |
| 监控闲置服务 |
通过指标识别低使用率服务,合并或下线 |
💡 提示:Azure Cost Management 可与 Aspire Dashboard 联动,分析每服务成本。
10.4 本章小结
从第一章到第十章,我们完成了以下旅程:
✅ 架构设计:使用 Aspire 编排微服务、数据库、中间件;
✅ 开发效率:一键启动完整环境,告别“在我机器上能跑”;
✅ 可观测性:Logs/Metrics/Traces 开箱即用;
✅ 安全体系:OIDC、mTLS、零信任实践;
✅ 质量保障:单元、集成、E2E、混沌测试全覆盖;
✅ 性能扩展:缓存、异步、自动扩缩容;
✅ 生产落地:多环境管理、成本控制、平滑迁移;
✅ 面向未来:拥抱 AI、Serverless、多云。
.NET Aspire 不仅是一个工具,更是一种 现代云原生开发范式。它让 .NET 开发者能够以极低的认知负荷,构建高可靠、高性能、易维护的分布式系统。