Aspire 项目实战:BoardApp 传统 .NET LOB 应用的架构解析与手动部署指南
2026/9/18 4:44:06 网站建设 项目流程

Aspire 项目实战:BoardApp 传统 .NET LOB 应用的架构解析与手动部署指南

【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire

导读

本文基于 Aspire 开源仓库中的示例应用BoardApp(dotnet-traditional),完整讲解一个典型的"传统 .NET 业务线(LOB)应用"应如何搭建与手动运行:它由 Vue 3 前端、ASP.NET 最小 API、Blazor Server 管理后台、EF Core 迁移 Worker 与共享数据层组成,并依赖 PostgreSQL 与 Redis。读完本文,你将掌握该应用的整体架构、.env配置体系、5 个关键端口的启动流程与验证方法,并理解它作为aspireify技能评测"前状态"(pre-aspirification)样本的设计意图,为后续用 Aspire 编排同类应用打下对照基础。

应用定位:Aspirify 评测的"前状态"样本

BoardApp 位于仓库的 playground/aspireify-eval/dotnet-traditional/ 目录,是 Aspire 项目中专门用于评测aspireify技能的pre-aspirification(Aspirify 前)示例应用。它刻意不接入 Aspire,代表真实世界 LOB 应用迁移前的形态:

  • 它拥有一个含多个 .NET 项目与 Vue 前端的完整解决方案;
  • 所有配置散落在根目录.env中,各服务通过环境变量自行读取;
  • 启动依赖人工维护多个终端窗口、手工导出环境变量、按顺序启动基础设施与各服务。

根据父目录 playground/aspireify-eval/README.md 的说明,评测流程是:进入该应用目录 → 执行aspire init→ 让 Agent 使用aspireify技能将其完整 Aspirify(接入 Aspire 编排),并依据 EVAL-RUBRIC.md 打分。因此,本文描述的手动运行方式,正是评测中所指的"before"状态——理解它,才能对比出 Aspire 编排带来的差异。

架构总览

BoardApp 由 5 个组成部分构成,各部分职责清晰:

frontend/ → Vue 3 + Vite (port 5173),将 /api/* 代理到 BoardApi src/BoardApi/ → ASP.NET 最小 API (port 5220),EF Core + Postgres,Redis 缓存 src/AdminDashboard/→ Blazor Server (port 5230),与 BoardApi 共享同一数据库 src/MigrationRunner/→ Worker 服务,运行 EF Core 迁移后自动退出 src/BoardData/ → 类库,共享 EF Core DbContext 与模型 BoardApp.slnx → 将上述项目串联起来的解决方案文件 .env → 全部配置:DB 连接、Redis、API 密钥、机密

从实际源码可以进一步验证这一结构:

  • 解决方案文件 BoardApp.slnx 使用新的 slnx 格式,显式引用了BoardApiAdminDashboardMigrationRunnerBoardData四个 .csproj;
  • 共享数据层 src/BoardData/Models.cs 定义了BoardDbContext(含BoardItemsUserProfiles两个DbSet)以及BoardItemUserProfile两个实体模型;
  • 前端 frontend/vite.config.ts 将/api前缀的请求代理到process.env.API_URL(默认http://localhost:5220)。

数据流与协作关系

从源码调用关系可以推断出应用内部的数据协作方式:

  1. MigrationRunner最先启动,通过BoardDbContext执行EnsureCreatedAsync()建表,并在空库时写入种子数据(3 条BoardItem和 1 条UserProfile);
  2. BoardApi暴露 REST 端点,读写同一BoardDbContext,并通过StackExchange.RedisIConnectionMultiplexer访问 Redis;
  3. AdminDashboard作为管理端,同样直连数据库统计BoardItemsUserProfiles数量;
  4. 前端在开发期通过 Vite 代理把/api/*请求转发给 BoardApi,生产期则依赖同源部署。

依赖环境

运行 BoardApp 需要以下基础组件(均为本地开发环境要求):

依赖版本/端口要求用途
.NET SDK.NET 10(各 csproj 的 TargetFramework 为net10.0编译运行 4 个 .NET 项目
Node.js20+运行 Vite/Vue 前端
PostgreSQLlocalhost:5432主数据库
Redislocalhost:6379缓存(/api/cached-count端点)

各 .NET 项目均以net10.0为目标框架(参见 BoardApi.csproj),依赖Microsoft.EntityFrameworkCoreNpgsql.EntityFrameworkCore.PostgreSQLStackExchange.Redis等包;前端依赖vue@^3.5.0vite@^6.3.0@vitejs/plugin-vue(参见 frontend/package.json)。

配置体系:.env 与关键变量

BoardApp 的全部配置集中在仓库根目录的.env文件中,各 .NET 服务通过Environment.GetEnvironmentVariable()读取:

变量用途是否机密
DATABASE_URLPostgres 连接字符串是(含密码)
REDIS_URLRedis host:port
EXTERNAL_API_KEY第三方通知服务密钥
ADMIN_SECRET管理后台认证令牌
FEATURE_ENABLE_NOTIFICATIONS功能开关

从源码可以确认这些变量的实际消费方式:

  • BoardApi(src/BoardApi/Program.cs):读取DATABASE_URL配置 EF Core 的 Npgsql 提供程序;读取REDIS_URL建立ConnectionMultiplexer;读取EXTERNAL_API_KEY,缺失时直接throw new InvalidOperationException("EXTERNAL_API_KEY must be set")
  • AdminDashboard(src/AdminDashboard/Program.cs):读取DATABASE_URLADMIN_SECRET,后者缺失同样抛异常;
  • MigrationRunner(src/MigrationRunner/Program.cs):读取DATABASE_URL
  • 前端:在vite.config.ts中读取API_URL作为开发代理目标。

值得注意的一个细节是:各服务在环境变量缺失时都提供了指向本地默认值的回退(例如 BoardApi 与 MigrationRunner 默认连接Host=localhost;Port=5432;Database=boardapp;Username=postgres;Password=localdev123),但机密型变量(EXTERNAL_API_KEYADMIN_SECRET)则是硬性要求,这体现了"本地可快速跑通、生产强制注入机密"的常见工程模式。

手动运行指南(未接入 Aspire)

由于没有 Aspire 编排,运行整个应用需要4 个终端窗口2 个基础设施服务。下面按官方步骤逐步执行。

1. 启动基础设施

在终端 1 中依次启动 PostgreSQL 与 Redis 容器:

# 启动 Postgres(或复用已有实例) docker run -d --name boardapp-pg \ -e POSTGRES_PASSWORD=localdev123 \ -e POSTGRES_DB=boardapp \ -p 5432:5432 \ postgres:16 # 启动 Redis docker run -d --name boardapp-redis \ -p 6379:6379 \ redis:7

注意:Postgres 容器的密码localdev123与库名boardapp必须与代码中的默认连接字符串、.envDATABASE_URL保持一致,否则服务启动后无法连通数据库。

2. 加载环境变量

每个运行 .NET 服务的终端中先导出.env中的变量:

export $(cat .env | xargs)

该命令把.env每行的KEY=value逐条导出为进程环境变量;由于后续步骤会启动多个服务,因此每个终端都要单独执行一次。请确保在执行该命令前,终端工作目录位于存放.env的仓库根目录。

3. 运行数据库迁移

在终端 2 中运行迁移服务,它会在建表与种子数据写入完成后自动退出:

cd src/MigrationRunner dotnet run # 等待输出 "Migrations complete." 后该进程退出

从 MigrationRunner/Program.cs 可以看到它执行的是db.Database.EnsureCreatedAsync()(而非传统MigrateAsync()),随后在BoardItems为空时写入 3 条种子任务与 1 个管理员UserProfile,最后打印Migrations complete.。这一步必须最先完成,否则 BoardApi 与 AdminDashboard 查询时表还不存在。

4. 启动 API

迁移完成后,复用终端 2(或新开终端并重新export环境变量):

cd src/BoardApi dotnet run --urls http://localhost:5220

BoardApi 暴露的端点(来自 src/BoardApi/Program.cs)包括:

端点方法行为
/api/healthGET返回{"status":"healthy"}
/api/itemsGETCreatedAt倒序返回全部 BoardItem
/api/itemsPOST新增 BoardItem,返回 201 Created
/api/items/{id}GET按 Id 查询,未找到返回 404
/api/cached-countGET从 Redis 读取item-count字符串,验证 Redis 连通性
/api/notifyPOST桩实现,模拟调用第三方通知服务(使用EXTERNAL_API_KEY前缀)

5. 启动管理后台

在终端 3 中:

cd src/AdminDashboard dotnet run --urls http://localhost:5230

AdminDashboard 是 Blazor Server 应用(src/AdminDashboard/Program.cs),额外暴露/admin/health(返回带role="admin"的健康信息)与/admin/stats(统计 items/users 数量)两个最小 API 端点,并注册了MapBlazorHub()_Host回退页面。

6. 启动前端

在终端 4 中:

cd frontend npm install npm run dev # 打开 http://localhost:5173

Vite 开发服务器监听 5173 端口,并把所有/api/*请求代理到 BoardApi(可通过API_URL环境变量覆盖代理目标,参见 vite.config.ts)。

验证应用是否正常运行

全部服务启动后,可通过以下 URL 逐项验证(对应 README 中的验证清单):

  • 前端:http://localhost:5173 —— 应显示 "BoardApp" 及一列种子数据条目;
  • API 健康检查:http://localhost:5220/api/health —— 应返回{"status":"healthy"}
  • API 条目列表:http://localhost:5220/api/items —— 应返回种子 BoardItem 列表;
  • 管理统计:http://localhost:5230/admin/stats —— 应返回 item/user 数量;
  • Redis 缓存验证:http://localhost:5220/api/cached-count —— 测试 Redis 连通性(首次访问返回{"count":"not cached"},若已写入则返回缓存值)。

任何一项不符合预期,可按依赖顺序排查:先确认 Postgres/Redis 容器状态,再确认对应终端已执行export $(cat .env | xargs),最后核对端口占用(5220/5230/5173)与DATABASE_URL中的密码是否与容器一致。

从"Before"到"After":Aspirify 的评测意义

本文所述的整套手动流程(4 个终端 + 2 个基础设施 + 顺序启动 + 手工导环境变量)正是aspireify技能评测要消除的痛点。作为对照基准,这个 dotnet-traditional 应用刻意保持"未 Aspirify"状态,配套的评测体系位于 playground/aspireify-eval/EVAL-RUBRIC.md,评测人员在 polyglot/ 等样本上同样执行aspire init+aspireify技能流程后打分。

对读者而言,可以这样利用本仓库进行实践验证:先在本地按本文步骤把 BoardApp 手动跑通,再尝试在playground/aspireify-eval/dotnet-traditional目录执行aspire init,观察 Agent 如何把.env配置映射为 Aspire 资源、把 4 个 .NET 项目与前端纳管为分布式应用、把 4 个手工终端窗口收敛为一次dotnet run——前后两种运行方式的差异,就是 Aspire 编排价值最直观的体现。

【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询