.NET Aspire 云原生微服务实战:从本地开发到生产部署完整指南
作者:Crown_22 | 云原生 & .NET 开发者 | 技术分享
前言
2024年微软正式发布 .NET Aspire——一个专为云原生应用设计的开发框架。它不是又一个微服务框架,而是解决了微服务开发中最让人头疼的问题:本地开发体验。
传统微服务开发的痛点:
- 本地启动10个服务,每个都要单独配置
- 服务发现、数据库连接、消息队列的配置到处都是硬编码
- 本地环境和生产环境的配置差异巨大
- Dashboard 观测性工具部署复杂
.NET Aspire 的核心理念:用 C# 代码定义整个应用拓扑,一键启动本地开发环境,无缝迁移到生产。

一、.NET Aspire 架构全景
1.1 核心组件
┌─────────────────────────────────────────────────────┐
│ .NET Aspire Dashboard │
│ (Traces, Metrics, Logs, Console) │
└──────────────────────┬──────────────────────────────┘
│
┌──────────────────────┴──────────────────────────────┐
│ AppHost 项目 │
│ (编排器:定义所有服务和资源) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ Web API │ │ Worker │ │ Redis │ │ Postgres│ │
│ │ Service │ │ Service │ │ (资源) │ │ (资源) │ │
│ └──────────┘ └──────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────┘
│
┌──────────────────────┴──────────────────────────────┐
│ ServiceDefaults 项目 │
│ (OpenTelemetry, 服务发现, 健康检查, 弹性策略) │
└─────────────────────────────────────────────────────┘
1.2 项目结构
MyCloudApp/
├── src/
│ ├── MyApp.AppHost/ # 编排器项目
│ │ ├── Program.cs
│ │ └── MyApp.AppHost.csproj
│ ├── MyApp.ServiceDefaults/ # 服务默认配置
│ │ ├── Extensions.cs
│ │ └── MyApp.ServiceDefaults.csproj
│ ├── MyApp.ApiService/ # Web API 服务
│ │ ├── Program.cs
│ │ └── MyApp.ApiService.csproj
│ └── MyApp.WorkerService/ # 后台任务服务
│ ├── Program.cs
│ └── MyApp.WorkerService.csproj
├── tests/
└── MyApp.sln
二、从零搭建 Aspire 项目
2.1 创建项目
# 安装 Aspire 工作负载
dotnet workload install aspire
# 创建 Aspire 解决方案
dotnet new aspire-starter -n MyCloudApp
# 或者手动添加到现有项目
dotnet new aspire-apphost -n MyApp.AppHost
2.2 AppHost 编排器
// src/MyApp.AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);
// 添加基础设施资源
var postgres = builder.AddPostgres("postgres")
.WithDataVolume()
.WithPgAdmin(); // 开发时启用 PGAdmin 管理界面
var redis = builder.AddRedis("redis")
.WithDataVolume();
var rabbitmq = builder.AddRabbitMQ("rabbitmq")
.WithManagementPlugin();
// 添加数据库
var catalogDb = postgres.AddDatabase("catalogdb");
var orderDb = postgres.AddDatabase("orderdb");
// 添加微服务
var catalogApi = builder.AddProject<Projects.MyApp_CatalogService>("catalog-api")
.WithReference(catalogDb)
.WithReference(redis)
.WithHttpHealthCheck("/health");
var orderApi = builder.AddProject<Projects.MyApp_OrderService>("order-api")
.WithReference(orderDb)
.WithReference(rabbitmq)
.WithReference(catalogApi) // 服务间依赖
.WithHttpHealthCheck("/health");
var workerService = builder.AddProject<Projects.MyApp_WorkerService>("worker")
.WithReference(rabbitmq)
.WithReference(redis);
builder.Build().Run();
2.3 ServiceDefaults 配置
// src/MyApp.ServiceDefaults/Extensions.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
namespace Microsoft.Extensions.Hosting;
public static class Extensions
{
public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
{
builder.ConfigureOpenTelemetry();
builder.AddDefaultHealthChecks();
return builder;
}
private static void ConfigureOpenTelemetry(this IHostApplicationBuilder builder)
{
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
});
builder.Services.AddOpenTelemetry()
.ConfigureResource(resource => resource
.AddService(builder.Environment.ApplicationName))
.WithTracing(tracing => tracing
.AddAspNetCoreInstrumentation()
.AddGrpcClientInstrumentation()
.AddHttpClientInstrumentation()
.AddSource("MyApp.*"))
.WithMetrics(metrics => metrics
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation()
.AddMeter("MyApp.*"));
builder.Services.AddOpenTelemetry().UseOtlpExporter();
}
private static void AddDefaultHealthChecks(this IHostApplicationBuilder builder)
{
builder.Services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy());
}
}
三、微服务实现
3.1 Catalog Service(商品服务)
// src/MyApp.CatalogService/Program.cs
using Microsoft.EntityFrameworkCore;
using MyApp.CatalogService.Data;
using MyApp.CatalogService.Endpoints;
var builder = WebApplication.CreateBuilder(args);
// 服务注册
builder.AddServiceDefaults();
builder.AddNpgsqlDbContext<CatalogDbContext>("catalogdb");
builder.Services.AddStackExchangeRedisCache(builder.Configuration.GetConnectionString("redis")!);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// 中间件
app.MapDefaultEndpoints();
app.UseSwagger();
app.UseSwaggerUI();
// 数据库迁移
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<CatalogDbContext>();
await db.Database.MigrateAsync();
}
// 端点
app.MapCatalogEndpoints();
app.Run();
// src/MyApp.CatalogService/Models/Product.cs
namespace MyApp.CatalogService.Models;
public class Product
{
public int Id {
get; set; }
public string Name {
get; set; } = string.Empty;
public string Description {
get; set; } = string.Empty;
public decimal Price {
get


1259

被折叠的 条评论
为什么被折叠?



