找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

205

积分

0

好友

25

主题
发表于 昨天 02:55 | 查看: 3| 回复: 0

图片

图片

第一章: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
  • 本地开发时自动启动(http://localhost:17100
  • 实时查看服务状态、日志、依赖关系、指标
  • 支持跨服务追踪(Trace ID 透传)

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

  1. Docker 官网 下载并安装。
  2. 启动 Docker Desktop,确保状态为 “Running”。
  3. (可选)在设置中启用 “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 项目详解与代码剖析

2.6.1 App Host 项目(ECommercePlatform.AppHost)

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

✅ 注意:AddNpgsqlDbContextAddRedisClient 是 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 会:

  1. 构建所有项目;
  2. 启动 PostgreSQL 和 Redis 容器;
  3. 启动 ApiService 和 Web 前端;
  4. 自动打开 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 会:

  1. 在本地开发环境中,为 orderservice 分配一个内部 DNS 名称(即 "orderservice");
  2. 自动配置 HttpClient,使其能通过该名称解析到正确的 IP 和端口;
  3. 注入必要的遥测上下文(如 Trace ID)。
3.1.2 在服务中使用命名 HttpClient

WebFrontendProgram.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.AzureRabbitMQ.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 支持与 DaprService 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 MeshContainer Apps 自动提供 mTLS。

3.5 分布式上下文传播(Trace ID 透传)

这是 Aspire 可观测性的核心!

3.5.1 自动 Trace 传播

当你在 Web 前端发起请求:

  1. Aspire 自动生成一个 Trace ID;
  2. 调用 HttpClient 时,自动在 Header 中添加 traceparent;
  3. ApiService 收到请求后,将其作为子 Span 记录;
  4. 所有日志自动关联该 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 对数据库的支持遵循三大原则:

  1. 声明式资源定义:在 App Host 中用 C# 代码声明数据库类型、版本、配置,无需手动编写 docker-compose.yml 或 Kubernetes YAML。
  2. 自动连接注入:通过 .WithReference() 自动将连接字符串或客户端实例注入到目标服务,避免硬编码。
  3. 开箱即用的可观测性:所有数据库操作(查询、命令)自动记录为 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
        });
    }
}

OrderServiceProgram.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_idspan_id
  • 级别过滤:可在 Dashboard 中按 Info/Warning/Error 筛选。
5.2.3 在 Aspire Dashboard 查看日志
  1. 打开 http://localhost:17100
  2. 点击左侧 Logs
  3. 选择服务(如 orderservice)
  4. 实时流式显示,支持关键词搜索、时间范围筛选

💡 提示:点击任意日志行,可跳转到对应的 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)

使用 MeterCounter/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 中:

  1. 进入 Traces 标签页
  2. 点击任意 Trace ID
  3. 查看瀑布图:每个 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 会自动:

  1. 构建所有服务镜像并推送到 ACR(Azure Container Registry);
  2. 在 ACA 中创建应用实例;
  3. 创建 Azure Database for PostgreSQL、Azure Cache for Redis 等托管资源;
  4. 注入连接字符串和密钥;
  5. 配置 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;
});

🔑 AuthorizationMessageHandlerMicrosoft.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 网关 作为统一入口,集中处理:

  • TLS 终止
  • 身份验证
  • 速率限制
  • 日志与审计
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 中实现:

  1. 所有服务默认拒绝外部访问(仅 App Host 或网关可路由);
  2. 服务间通信强制认证(即使在同一 VPC);
  3. 最小权限原则:每个服务仅拥有必要权限;
  4. 持续监控:异常登录、高频失败请求触发告警。

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);
    }
}

✅ 使用 MoqNSubstitute 模拟接口,确保测试快速、稳定。

8.3 集成测试:Aspire 的杀手级特性

Aspire 提供 TestProjectDistributedApplicationTesting 包,允许在测试中 启动真实服务及其依赖(如 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)

🌿 逐步用新服务替换旧功能,而非一次性重写。

步骤:

  1. 识别边界:将单体应用拆分为业务域(如订单、用户、库存);
  2. 新建 Aspire 项目:作为新服务宿主;
  3. 反向代理路由:使用 YARP 或 API 网关,将新路径(如 /api/v2/orders)指向 Aspire 服务,旧路径仍走单体;
  4. 数据同步:初期可双写数据库,或通过 CDC(变更数据捕获)同步;
  5. 逐步下线:当新服务覆盖全部功能后,移除旧模块。
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 开发者能够以极低的认知负荷,构建高可靠、高性能、易维护的分布式系统。

您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区(YunPan.Plus) ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-1 13:33 , Processed in 0.082619 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 CloudStack.

快速回复 返回顶部 返回列表