.NET Aspire如何模拟企业K8s环境 - 实战演练
引言
在前两篇文章中,我们讨论了为什么需要多智能体协作系统,以及如何使用MCP、A2A和Agent Framework实现智能体间的标准化通信。但有一个实际问题还没有解决:
开发一个由5个微服务+前端组成的系统,本地怎么调试?
想象一下传统的开发场景:
# 终端窗口1
cd Finance
dotnet run --urls "https://localhost:7043"# 终端窗口2
cd Tech
dotnet run --urls "https://localhost:7063"# 终端窗口3
cd HumanResource
dotnet run --urls "https://localhost:7202"# 终端窗口4
cd QA
dotnet run --urls "https://localhost:7153"# 终端窗口5
cd PMO
dotnet run --urls "https://localhost:7125"# 终端窗口6
cd AgentFrameworkAspire.Web
dotnet run --urls "https://localhost:7223"
6个终端窗口、6组命令、需要记住6个端口号、配置6次OpenAI API Key...
更糟糕的是:
- 如何确保服务按正确顺序启动?
- 如何让Web前端自动发现其他服务的URL?
- 如何统一查看所有服务的日志?
- 如何追踪跨服务的请求链路?
这就是.NET Aspire要解决的问题。
一、什么是.NET Aspire?
1.1 官方定义
.NET Aspire是一个云原生应用开发栈,专为.NET设计,旨在简化分布式应用的开发、测试和部署。
但这个定义太官方了。用人话说:
Aspire = Docker Compose + 服务发现 + 配置管理 + 可视化Dashboard + 一键部署
1.2 核心价值
痛点 | 传统方案 | Aspire解决方案 |
---|---|---|
启动多服务 | 打开多个终端,逐个启动 | 一行命令启动所有 |
端口管理 | 手动指定端口,冲突频发 | 自动分配动态端口 |
配置共享 | 每个服务都要配置一遍 | 参数定义一次,自动注入 |
服务发现 | 硬编码URL或手动配置 | 自动服务发现 |
日志查看 | 切换窗口查看不同服务 | Dashboard统一查看 |
分布式追踪 | 需要额外配置APM工具 | 内置OpenTelemetry |
部署到云 | 写Dockerfile、K8s manifest | 一行命令部署到ACA |
1.3 Aspire vs Kubernetes架构对比
关键对比:
维度 | Aspire本地开发 | Kubernetes本地开发 |
---|---|---|
启动复杂度 | ✅ 一行命令:dotnet run |
❌ 多步骤:构建镜像→编写YAML→kubectl apply |
运行环境 | ✅ 直接运行.NET进程 | ❌ 需要Docker + K8s集群 |
配置管理 | ✅ C#代码配置(类型安全) | ❌ YAML配置(易出错) |
服务发现 | ✅ 自动注入环境变量 | ⚠️ 需要配置Service和DNS |
可视化 | ✅ 内置Dashboard | ⚠️ 需要安装额外工具 |
学习成本 | ✅ .NET开发者友好 | ❌ 需要学习容器和K8s概念 |
调试体验 | ✅ 原生.NET调试器 | ⚠️ 远程调试或日志调试 |
生产部署路径:
-
Aspire路径:
- 本地:Aspire AppHost
- 生产:
azd deploy
→ Azure Container Apps(自动生成容器镜像、配置、网络)
-
Kubernetes路径:
- 本地:Minikube/Docker Desktop + YAML
- 生产:
kubectl apply
→ Kubernetes集群(手动编写所有配置)
结论:
- Aspire适合 .NET团队快速开发和Azure生态
- Kubernetes适合多语言团队和混合云环境
- 两者不是非此即彼:Aspire也可以生成Kubernetes manifest
1.4 Aspire的核心价值
痛点 | 传统方案 | Aspire解决方案 |
---|---|---|
启动多服务 | 打开多个终端,逐个启动 | 一行命令启动所有 |
端口管理 | 手动指定端口,冲突频发 | 自动分配动态端口 |
配置共享 | 每个服务都要配置一遍 | 参数定义一次,自动注入 |
服务发现 | 硬编码URL或手动配置 | 自动服务发现 |
日志查看 | 切换窗口查看不同服务 | Dashboard统一查看 |
分布式追踪 | 需要额外配置APM工具 | 内置OpenTelemetry |
部署到云 | 写Dockerfile、K8s manifest | 一行命令部署到ACA |
二、AgentFrameworkAspire中的Aspire配置
2.1 项目结构
AgentFrameworkAspire/
├── AgentFrameworkAspire.AppHost/ ← Aspire编排器
│ ├── Program.cs ← 核心配置文件
│ └── appsettings.json
├── AgentFrameworkAspire.ServiceDefaults/ ← 共享配置
│ ├── Extensions.cs
│ └── AgentHelpers.cs
├── Finance/ ← 微服务1
├── Tech/ ← 微服务2
├── HumanResource/ ← 微服务3
├── QA/ ← 微服务4
├── PMO/ ← 微服务5
└── AgentFrameworkAspire.Web/ ← Web前端
关键角色:
- AppHost:指挥官,负责编排所有服务
- ServiceDefaults:后勤部,提供共享配置和辅助方法
- 各微服务:士兵,实际执行任务
2.2 AppHost的核心配置
让我们深入AgentFrameworkAspire.AppHost/Program.cs
:
var builder = DistributedApplication.CreateBuilder(args);// ============================================================
// 第一部分:参数定义(Parameter Definition)
// ============================================================// openai-endpoint:可选参数,默认为官方API
var openAiEndpoint = builder.AddParameter("openai-endpoint", "https://api.vveai.com/v1" // 默认值,可以留空表示使用OpenAI官方
);// openai-apikey:密钥参数,不会明文显示
var openAiApiKey = builder.AddParameter("openai-apikey", secret: true // 标记为敏感信息
);// openai-deployment:模型名称,默认gpt-4o-mini
var openAiDeploymentName = builder.AddParameter("openai-deployment", "gpt-4o-mini"
);// ============================================================
// 第二部分:微服务定义(Microservices Configuration)
// ============================================================// Finance 服务
var financeService = builder.AddProject<Projects.Finance>("finance").WithEnvironment("OpenAI__Endpoint", openAiEndpoint).WithEnvironment("OpenAI__ApiKey", openAiApiKey).WithEnvironment("OpenAI__DeploymentName", openAiDeploymentName);// HR 服务
var hrService = builder.AddProject<Projects.HumanResource>("humanresource").WithEnvironment("OpenAI__Endpoint", openAiEndpoint).WithEnvironment("OpenAI__ApiKey", openAiApiKey).WithEnvironment("OpenAI__DeploymentName", openAiDeploymentName);// QA 服务
var qaService = builder.AddProject<Projects.QA>("qa").WithEnvironment("OpenAI__Endpoint", openAiEndpoint).WithEnvironment("OpenAI__ApiKey", openAiApiKey).WithEnvironment("OpenAI__DeploymentName", openAiDeploymentName);// Tech 服务
var techService = builder.AddProject<Projects.Tech>("tech").WithEnvironment("OpenAI__Endpoint", openAiEndpoint).WithEnvironment("OpenAI__ApiKey", openAiApiKey).WithEnvironment("OpenAI__DeploymentName", openAiDeploymentName);// PMO 服务
var pmoService = builder.AddProject<Projects.PMO>("pmo").WithEnvironment("OpenAI__Endpoint", openAiEndpoint).WithEnvironment("OpenAI__ApiKey", openAiApiKey).WithEnvironment("OpenAI__DeploymentName", openAiDeploymentName);// ============================================================
// 第三部分:Web前端配置(Web Frontend Configuration)
// ============================================================builder.AddProject<Projects.AgentFrameworkAspire_Web>("webfrontend").WithExternalHttpEndpoints() // 允许外部访问.WithEnvironment("OpenAI__Endpoint", openAiEndpoint).WithEnvironment("OpenAI__ApiKey", openAiApiKey).WithEnvironment("OpenAI__DeploymentName", openAiDeploymentName)// 引用所有specialist服务(实现服务发现).WithReference(techService).WithReference(hrService).WithReference(financeService).WithReference(qaService).WithReference(pmoService)// 等待所有服务就绪后再启动.WaitFor(techService).WaitFor(hrService).WaitFor(financeService).WaitFor(qaService).WaitFor(pmoService);builder.Build().Run();
关键API解析:
AddParameter()
- 参数定义
var param = builder.AddParameter(name: "openai-apikey", // 参数名(会提示用户输入或从配置读取)secret: true // 是否是密钥(敏感信息)
);
效果:
- 如果没有在User Secrets中配置,启动时会提示输入
secret: true
的参数输入时不显示明文- 参数可以传递给任何服务
AddProject<T>()
- 添加服务
var service = builder.AddProject<Projects.Finance>("finance");
效果:
- Aspire会自动发现
Finance.csproj
- 自动编译和启动该项目
- 分配动态端口(避免冲突)
WithEnvironment()
- 注入环境变量
service.WithEnvironment("OpenAI__ApiKey", openAiApiKey);
效果:
- 将参数作为环境变量注入到服务进程
- 服务中通过
IConfiguration
自动读取 - 使用
__
(双下划线)表示层级结构(OpenAI:ApiKey
)
WithReference()
- 服务引用
webfrontend.WithReference(financeService);
效果:
- 自动注入环境变量:
services__finance__http__0=http://localhost:xxxx
- Web前端可以通过配置自动发现Finance服务的URL
- 支持HTTP和HTTPS端点
WaitFor()
- 启动依赖
webfrontend.WaitFor(financeService);
效果:
- Web前端会等待Finance服务启动完成
- 确保服务按正确顺序启动
- 避免"服务未就绪"错误
2.3 Aspire服务发现机制图解
下面展示Aspire如何实现服务间的自动发现和通信:
服务发现流程详解:
-
AppHost编排阶段:
- AppHost通过
AddProject()
注册各个微服务 - Aspire为每个服务动态分配端口(避免硬编码)
- 通过
WithReference()
建立服务依赖关系
- AppHost通过
-
环境变量注入:
- Aspire自动生成服务发现环境变量
- 格式:
services__<服务名>__<协议>__<索引>
=URL
- Web服务启动时自动读取这些环境变量到
IConfiguration
-
Service Discovery解析:
- Web服务中的
HttpClient
配置了AddServiceDiscovery()
- 当代码请求
http://finance
时,Service Discovery拦截请求 - 从配置中查找实际URL并重写请求
- Web服务中的
-
实际通信:
- HttpClient使用解析后的真实URL(如
https://localhost:7222
) - 请求到达目标服务
- 支持负载均衡、重试、断路器等弹性功能
- HttpClient使用解析后的真实URL(如
代码映射:
// AppHost/Program.cs - 编排层
var financeService = builder.AddProject<Projects.Finance>("finance");
var webfrontend = builder.AddProject<Projects.AgentFrameworkAspire_Web>("webfrontend").WithReference(financeService); // 这里触发服务发现配置注入// Web/Program.cs - 消费层
builder.Services.AddHttpClient("FinanceClient", client =>
{client.BaseAddress = new Uri("http://finance"); // 使用服务名而非硬编码URL
});
2.4 ServiceDefaults的共享配置
每个微服务都引用了AgentFrameworkAspire.ServiceDefaults
项目,它提供了:
// AgentFrameworkAspire.ServiceDefaults/Extensions.cs
public static class Extensions
{public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder){// 配置 OpenTelemetry(分布式追踪)builder.ConfigureOpenTelemetry();// 配置健康检查builder.AddDefaultHealthChecks();// 配置服务发现builder.Services.AddServiceDiscovery();// 配置HTTP客户端(支持服务发现)builder.Services.ConfigureHttpClientDefaults(http =>{http.AddStandardResilienceHandler(); // 添加重试、断路器等http.AddServiceDiscovery(); // 支持通过服务名调用});return builder;}
}
每个微服务只需一行代码:
// Finance/Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults(); // ← 添加所有标准配置
三、实战:从零启动系统
3.1 前置要求检查
# 检查 .NET SDK 版本
dotnet --version
# 应该显示 9.0.x 或更高# 检查 Aspire Workload(首次使用需要安装)
dotnet workload list
# 如果没有 aspire,执行:
dotnet workload install aspire
3.2 克隆项目
git clone https://github.com/microsoft/agent-framework.git
cd AgentFrameworkAspire
3.3 配置OpenAI API密钥
cd AgentFrameworkAspire.AppHost# 初始化 User Secrets
dotnet user-secrets init# 配置参数(以Azure OpenAI为例)
dotnet user-secrets set "Parameters:openai-endpoint" "https://your-resource.openai.azure.com/"
dotnet user-secrets set "Parameters:openai-apikey" "your-api-key-here"
dotnet user-secrets set "Parameters:openai-deployment" "gpt-4o"
验证配置:
dotnet user-secrets list
应该显示:
Parameters:openai-endpoint = https://your-resource.openai.azure.com/
Parameters:openai-apikey = ********************************
Parameters:openai-deployment = gpt-4o
3.4 启动系统
方式1:Visual Studio
- 打开
AgentFrameworkAspire.slnx
- 设置
AgentFrameworkAspire.AppHost
为启动项目 - 按
F5
启动调试 - Dashboard会自动在浏览器打开
方式2:命令行
cd AgentFrameworkAspire.AppHost
dotnet run
3.5 访问Aspire Dashboard
启动成功后,浏览器会自动打开Dashboard:http://localhost:xxxxx
如果没有自动打开,手动访问即可。
四、Aspire Dashboard深度导览
Dashboard是Aspire最强大的功能之一,让我们逐一探索。
4.1 Resources(资源视图)
这是默认页面,显示所有服务的状态:
功能:
- State(状态):Running、Starting、Stopped、Failed
- Endpoints(端点):点击直接访问服务
- Logs(日志):查看实时日志
- Details(详情):查看环境变量、配置等
点击服务名称,可以看到详细信息:
4.2 Console Logs(日志视图)
点击任一服务的"Logs"按钮,进入日志页面:
功能:
- 实时滚动显示日志
- 支持日志级别过滤(Info、Warning、Error)
- 支持搜索关键词
- 支持下载日志文件
多服务日志对比:
可以同时打开多个服务的日志,放在不同标签页:
[Tab: finance] [Tab: tech] [Tab: webfrontend]↓ ↓ ↓Finance日志 Tech日志 Web前端日志
这样可以对比时间戳,追踪跨服务的调用链。
4.3 Traces(追踪视图)
这是分布式追踪功能,展示请求在服务间的流转:
示例场景:用户在Web UI提交一个项目规划请求
价值:
- 性能分析:找出最慢的服务(这里是QA,9.5秒)
- 错误定位:如果某个服务返回500,一目了然
- 并行验证:确认Stage 1的4个服务确实是并行执行的
点击任一Span,可以看到详细信息:
4.4 Metrics(指标视图)
展示服务的性能指标:
五、服务发现的魔法
5.1 Aspire如何注入服务URL?
当你在AppHost中写:
builder.AddProject<Projects.AgentFrameworkAspire_Web>("webfrontend").WithReference(financeService);
Aspire自动做的事情:
- Finance服务启动后,Aspire获取其端点(例如
https://localhost:7043
) - 生成环境变量:
services__finance__http__0=http://localhost:7043
- 将环境变量注入到webfrontend进程
5.2 Web前端如何解析服务URL?
在ProjectManagerAgent.cs
中:
// AgentFrameworkAspire.Web/Services/ProjectManagerAgent.cs
private string ResolveServiceUrl(string serviceName, string legacyConfigKey, string fallbackUrl)
{// 调试:列出所有 services__ 开头的配置var allServicesKeys = _configuration.AsEnumerable().Where(kv => kv.Key != null && kv.Key.StartsWith("services__")).ToList();if (allServicesKeys.Any()){_logger.LogDebug("Found {Count} service discovery keys", allServicesKeys.Count);foreach (var kv in allServicesKeys){_logger.LogDebug(" {Key} = {Value}", kv.Key, kv.Value ?? "(null)");}}// 1. 尝试Aspire服务发现格式: services__{serviceName}__https__0var aspireHttpsKey = $"services__{serviceName}__https__0";var httpsUrl = _configuration[aspireHttpsKey];if (!string.IsNullOrEmpty(httpsUrl)){_logger.LogInformation("Resolved {ServiceName} via Aspire HTTPS: {Url}", serviceName, httpsUrl);// 从 fallbackUrl 中提取路径部分 (例如 /tech/requirement-analyst)var uri = new Uri(fallbackUrl);var path = uri.PathAndQuery;return $"{httpsUrl.TrimEnd('/')}{path}";}// 2. 尝试Aspire服务发现格式: services__{serviceName}__http__0var aspireHttpKey = $"services__{serviceName}__http__0";var httpUrl = _configuration[aspireHttpKey];if (!string.IsNullOrEmpty(httpUrl)){_logger.LogInformation("Resolved {ServiceName} via Aspire HTTP: {Url}", serviceName, httpUrl);var uri = new Uri(fallbackUrl);var path = uri.PathAndQuery;return $"{httpUrl.TrimEnd('/')}{path}";}// 3. 尝试传统配置格式var legacyUrl = _configuration[legacyConfigKey];if (!string.IsNullOrEmpty(legacyUrl)){_logger.LogInformation("Resolved {ServiceName} via legacy config: {Url}", serviceName, legacyUrl);return legacyUrl;}// 4. 使用fallback_logger.LogWarning("Using fallback URL for {ServiceName}: {Url}", serviceName, fallbackUrl);return fallbackUrl;
}
调用示例:
_financeAgentUrl = ResolveServiceUrl("finance", // Aspire服务名"SpecialistAgents:Finance", // 传统配置key"https://localhost:7043/finance/budget-analyzer" // Fallback URL
);
解析过程:
1. 尝试 services__finance__https__0✅ 找到: https://localhost:7043→ 拼接路径: https://localhost:7043/finance/budget-analyzer2. 如果没找到HTTPS,尝试 services__finance__http__03. 如果都没找到,尝试 appsettings.json:SpecialistAgents:Finance4. 最后使用 fallback URL
好处:
- Aspire环境:自动服务发现,无需配置
- 本地调试:可以在appsettings.json中硬编码URL
- 单元测试:使用fallback URL,不依赖真实服务
六、实战场景演练
6.1 场景1:添加新服务
假设你要添加一个"Legal(法务)"服务。
步骤1:创建项目
dotnet new webapi -n Legal
cd Legal
dotnet add package A2A.AspNetCore
dotnet add package ModelContextProtocol.Server
步骤2:在AppHost中注册
// AgentFrameworkAspire.AppHost/Program.cs
var legalService = builder.AddProject<Projects.Legal>("legal").WithEnvironment("OpenAI__Endpoint", openAiEndpoint).WithEnvironment("OpenAI__ApiKey", openAiApiKey).WithEnvironment("OpenAI__DeploymentName", openAiDeploymentName);builder.AddProject<Projects.AgentFrameworkAspire_Web>("webfrontend")// ... 其他引用.WithReference(legalService) // ← 添加这行.WaitFor(legalService); // ← 添加这行
完成! 重新启动AppHost,Legal服务会自动加入编排。
6.2 场景2:修改OpenAI配置
假设你想换成本地的Ollama模型。
步骤1:确保Ollama运行
ollama serve
ollama pull llama3
步骤2:更新User Secrets
cd AgentFrameworkAspire.AppHost
dotnet user-secrets set "Parameters:openai-endpoint" "http://localhost:11434/v1/"
dotnet user-secrets set "Parameters:openai-apikey" "ollama"
dotnet user-secrets set "Parameters:openai-deployment" "llama3"
步骤3:重启系统
dotnet run
所有6个服务自动切换到Ollama,无需修改代码!
6.3 场景3:调试单个服务
有时你只想调试Finance服务,不想启动整个系统。
选项1:临时禁用其他服务
// AgentFrameworkAspire.AppHost/Program.cs
// var techService = builder.AddProject<Projects.Tech>("tech") // 注释掉
// .WithEnvironment...;
选项2:直接运行单个服务
cd Finance
$env:OpenAI__Endpoint = "https://your-resource.openai.azure.com/"
$env:OpenAI__ApiKey = "your-api-key"
$env:OpenAI__DeploymentName = "gpt-4o"
dotnet run
然后用Postman测试A2A端点。
6.4 场景4:查看跨服务调用链
步骤1:在Web UI发送请求
用户输入:开发一个电商系统,预算200万,12个月
步骤2:打开Dashboard的Traces页面
选择最新的trace,你会看到:
webfrontend: ExecuteWorkflowStreamAsync (28.5s)├─ tech: ProcessMessageAsync (7.8s)│ └─ OpenAI API call (6.5s)├─ hr: ProcessMessageAsync (6.2s)│ └─ OpenAI API call (5.1s)├─ finance: ProcessMessageAsync (7.1s)│ ├─ MCP: ValidateBudget (0.05s)│ ├─ MCP: GetHistoricalCosts (0.03s)│ └─ OpenAI API call (5.9s)└─ qa: ProcessMessageAsync (9.5s)└─ Workflow execution (8.8s)├─ RiskIdentifier (2.1s)├─ ImpactAnalyzer (2.3s)├─ MitigationPlanner (2.2s)└─ MonitoringPlanner (2.2s)
发现:
- QA服务最慢(9.5秒),因为它内部有4阶段工作流
- Finance调用了2个MCP工具,非常快(<0.1秒)
- 大部分时间花在OpenAI API调用上(5-6秒每次)
七、最佳实践与技巧
7.1 参数命名规范
// ✅ 好的命名:小写,短横线分隔
builder.AddParameter("openai-endpoint");
builder.AddParameter("database-connection-string");// ❌ 不好的命名:大写、下划线
builder.AddParameter("OPENAI_ENDPOINT");
builder.AddParameter("database_connection_string");
7.2 敏感信息标记
// ✅ API Key、密码等标记为secret
var apiKey = builder.AddParameter("api-key", secret: true);// ✅ 普通配置不标记
var endpoint = builder.AddParameter("api-endpoint");
7.3 服务启动顺序
// ✅ 明确依赖关系
webfrontend.WithReference(financeService) // 声明依赖.WaitFor(financeService); // 等待就绪// ❌ 不声明依赖,可能出现"服务未找到"错误
webfrontend.WithReference(financeService); // 只声明,不等待
7.4 环境变量命名
// ✅ 使用双下划线表示层级
.WithEnvironment("OpenAI__Endpoint", endpoint)
.WithEnvironment("OpenAI__ApiKey", apiKey)// 对应的配置结构:
// {
// "OpenAI": {
// "Endpoint": "...",
// "ApiKey": "..."
// }
// }
7.5 日志级别控制
// appsettings.Development.json
{"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning","Aspire.Hosting": "Information"}}
}
八、常见问题排查
问题1:服务无法启动
症状:Dashboard显示服务状态为"Failed"
排查步骤:
- 点击服务名称,查看"Console Logs"
- 查找错误消息(通常是红色)
- 常见原因:
- 端口被占用(切换到动态端口)
- OpenAI配置错误(检查User Secrets)
- 依赖包缺失(
dotnet restore
)
示例错误:
[ERROR] Failed to start application
System.InvalidOperationException: OpenAI__ApiKey is not configured
解决:检查User Secrets配置。
问题2:服务发现失败
症状:Web前端报错"Unable to connect to tech service"
排查步骤:
- 在Dashboard确认Tech服务正在运行
- 查看Web前端的环境变量(Dashboard → webfrontend → Details)
- 检查是否有
services__tech__http__0
变量 - 如果没有,检查AppHost的
WithReference(techService)
问题3:Dashboard无法访问
症状:http://localhost:15000
无法打开
可能原因:
- Dashboard端口被占用
- AppHost启动失败
解决:
# 查看AppHost进程是否运行
Get-Process -Name "AgentFrameworkAspire.AppHost" -ErrorAction SilentlyContinue# 如果没有,查看启动日志
cd AgentFrameworkAspire.AppHost
dotnet run --verbose
问题4:OpenAI调用超时
症状:服务日志显示"Request timeout"
排查:
- 检查网络连接
- 检查Endpoint URL格式(应以
/
结尾) - 检查API Key是否有效
- 尝试直接用curl测试:
curl -X POST "https://your-resource.openai.azure.com/openai/deployments/gpt-4/chat/completions?api-version=2024-08-01-preview" `-H "api-key: your-key" `-H "Content-Type: application/json" `-d '{"messages":[{"role":"user","content":"Hello"}]}'
九、进阶技巧
9.1 多环境配置
// AgentFrameworkAspire.AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);// 根据环境读取不同配置
var environment = builder.Environment.EnvironmentName;if (environment == "Development")
{// 开发环境:使用本地Ollamavar endpoint = "http://localhost:11434/v1/";
}
else if (environment == "Staging")
{// 测试环境:使用Azure OpenAI测试资源var endpoint = builder.Configuration["AzureOpenAI:StagingEndpoint"];
}
else if (environment == "Production")
{// 生产环境:使用Azure OpenAI生产资源var endpoint = builder.Configuration["AzureOpenAI:ProductionEndpoint"];
}
9.2 条件服务注册
// 只在开发环境启动某些服务
if (builder.Environment.IsDevelopment())
{builder.AddProject<Projects.TestService>("testservice");
}
9.3 自定义健康检查
// Finance/Program.cs
builder.Services.AddHealthChecks().AddCheck("openai", () =>{// 检查OpenAI连接try{var client = AgentHelpers.CreateChatClient(builder.Configuration);// 简单测试return HealthCheckResult.Healthy();}catch{return HealthCheckResult.Unhealthy("Cannot connect to OpenAI");}});
9.4 资源限制
// 限制服务资源使用(仅Container模式)
var financeService = builder.AddContainer("finance", "finance-image").WithEnvironment(...).WithResourceLimits(memory: 512, cpu: 0.5); // 512MB内存,0.5核CPU
十、总结
Aspire的核心价值
- 简化本地开发:一行命令启动所有服务
- 统一配置管理:参数定义一次,自动注入
- 自动服务发现:无需硬编码URL
- 可视化监控:Dashboard实时查看状态、日志、追踪
- 生产就绪:一键部署到Azure或生成K8s manifest
与其他方案对比
场景 | 传统方式 | Docker Compose | Aspire |
---|---|---|---|
启动服务 | 6个终端 | 1条命令 | 1条命令 |
配置管理 | 重复配置 | .env文件 | 参数系统 |
服务发现 | 硬编码 | Docker网络 | 自动注入 |
日志查看 | 切换窗口 | docker logs | Dashboard |
分布式追踪 | 额外工具 | 需要配置 | 内置 |
.NET集成 | 一般 | 一般 | 原生 |
学习曲线 | 低 | 中 | 低 |
下一步
在下一篇文章中,我们将讨论:
- 如何将Demo系统改造为生产就绪
- 需要添加哪些功能(认证、缓存、测试)
- 如何部署到Azure Container Apps
- 性能优化和成本控制
参考资料
- .NET Aspire官方文档:https://learn.microsoft.com/dotnet/aspire/
- AgentFrameworkAspire项目:https://github.com/microsoft/agent-framework
- Azure Container Apps:https://learn.microsoft.com/azure/container-apps/
- OpenTelemetry:https://opentelemetry.io/