NET_Aspire云原生微服务实战:从本地开发到生产部署完整指南

.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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值