ABP vNext 标准分层解决方案项目结构完整解析
这是 ABP CLI 一键生成的完整分层式(Tiered)多模板解决方案 ,包含领域层、应用层、API、认证服务、Blazor多套UI、数据库迁移、客户端代理等全套模块,下面按职责分类拆解每个项目。

一、核心领域分层(DDD 基础四层,业务核心)
1. MyCompany.MyProject.Domain.Shared(领域共享层)
最小粒度共享程序集,无依赖污染
- 存放:枚举、常量、异常码、本地化资源、共享DTO接口、权限常量、业务常量
- 引用范围:所有项目都会引用它,不能依赖任何业务实现层,只放纯定义
- 示例:订单状态枚举、错误Code、系统权限字符串、多语言
.json资源文件
2. MyCompany.MyProject.Domain(领域层,DDD核心)
业务领域模型、聚合根、领域服务、领域事件
- 核心内容:实体(AggregateRoot)、值对象、仓储接口
IRepository、领域服务DomainService、领域事件定义、业务规则校验 - 只依赖
Domain.Shared,不依赖数据库、API、UI,纯业务逻辑,与技术无关 - 职责:承载核心业务规则,比如订单创建校验库存、会员等级计算逻辑
3. MyCompany.MyProject.Application.Contracts(应用契约层)
前后端/服务之间的数据契约,接口定义
- 存放:应用服务接口
IXXXAppService、输入DTO(CreateXXXDto)、输出DTO(XXXDto)、查询分页对象 - 仅依赖
Domain.Shared,不包含任何业务实现,是API对外暴露的"接口契约" - 作用:给前端/第三方客户端提供强类型调用约定,HttpApi.Client 会根据它生成代理
4. MyCompany.MyProject.Application(应用服务层)
业务流程编排,DDD应用层
- 实现
Application.Contracts里的所有IXXXAppService接口 - 依赖:Domain(仓储、领域服务)+ Application.Contracts
- 职责:事务控制、DTO映射、调用领域层、权限校验、工作流编排,不写核心业务规则,只做流程组装
- 示例:创建订单AppService:校验用户权限 → 调用领域订单创建 → 扣减库存领域服务 → 发送领域事件
二、数据持久层(数据库实现)
MyCompany.MyProject.EntityFrameworkCore(EF Core 数据库实现)
- 实现 Domain 层定义的所有
IRepository仓储接口 - 包含:
DbContext、实体与数据库表映射配置、数据种子(Seed)、EF迁移脚本 - 依赖 Domain、Domain.Shared
- 仅用于SQL Server/MySQL等关系型数据库
MyCompany.MyProject.MongoDB(MongoDB 持久化实现)
- MongoDB仓储实现,和EntityFrameworkCore二选一或共存
- 存放Mongo DbContext、实体映射、Mongo仓储实现
MyCompany.MyProject.DbMigrator(数据库迁移控制台工具)
独立控制台程序,上线执行数据库初始化/迁移
- 执行EF迁移,创建/更新数据库表
- 初始化种子数据:管理员账号、默认租户、权限、系统配置、初始化字典
- 部署流水线专用,不依赖Web服务,单独运行完成库初始化
三、API 网关 & 客户端代理(前后端通信)
1. MyCompany.MyProject.HttpApi(API控制器层)
RESTful API 对外暴露层
- 自动把 Application AppService 转为 Controller,ABP自动路由
- 仅做转发:接收Http请求 → 调用对应AppService → 返回DTO
- 依赖 Application、Application.Contracts
- 不写业务逻辑,纯http适配层
2. MyCompany.MyProject.HttpApi.Client(红标重点,HTTP客户端代理)
强类型API调用客户端,给UI/第三方服务调用后端API
- 根据
Application.Contracts自动生成C#代理类,封装HttpClient请求 - 项目内包含动态客户端生成代码,Blazor、第三方微服务直接引用调用接口,不用手写Http请求
- 核心价值:前端C#项目(Blazor)无需重复定义DTO和请求逻辑,直接像本地方法一样调用远程AppService
3. MyCompany.MyProject.HttpApi.Host / HttpApi.HostWithIds
API独立宿主(分层架构专用)
HttpApi.Host:独立API服务启动项目,发布为单独后端接口服务HttpApi.HostWithIds:集成OpenIddict身份服务一体的API宿主(一体化架构,API+认证在一个站点)- 配置跨域、Swagger、授权、路由,对外提供接口访问地址
四、认证授权服务(AuthServer 统一身份中心)
MyCompany.MyProject.AuthServer(独立身份认证服务)
Tiered分层架构专用,独立的OpenIddict认证中心
- 单独部署的登录授权站点,负责颁发JWT、账号密码登录、第三方登录、客户端授权
- API、Blazor前端全部对接这个服务做统一身份认证,实现单点登录
- 一体化架构(非分层)会把认证逻辑合并到Web/ApiHost,分层架构拆分独立AuthServer
五、Blazor UI 多套前端项目(ABP内置三种Blazor模式)
Blazor分为 Server、WebAssembly(Client)、WebApp 三种部署形态,Tiered代表分层架构(前端独立、对接远程Api)
1. MyCompany.MyProject.Blazor(基础Blazor共享层)
Blazor页面共享组件、布局、公共UI逻辑、弹窗、菜单、权限组件,给下面所有Blazor项目引用
2. Blazor Server 模式
MyCompany.MyProject.Blazor.Server:一体化Blazor Server(和API同进程)MyCompany.MyProject.Blazor.Server.Tiered:分层Blazor Server(独立前端,远程调用HttpApi)
3. Blazor WebAssembly(WebApp)模式(前后端分离,wasm客户端)
MyCompany.MyProject.Blazor.WebApp.Client:WebAssembly客户端(浏览器运行)MyCompany.MyProject.Blazor.WebApp:一体化WebApp宿主MyCompany.MyProject.Blazor.WebApp.Tiered:分层WebApp宿主MyCompany.MyProject.Blazor.WebApp.Tiered.Client:分层架构下独立wasm客户端,引用HttpApi.Client调用远程API
4. Blazor.Client
纯WebAssembly客户端共享基础,存放wasm全局逻辑、认证状态管理、前端权限拦截
六、传统MVC/Razor页面Web项目(旧版UI,可选)
MyCompany.MyProject.Web / MyCompany.MyProject.Web.Host
传统ASP.NET Core Razor Pages / MVC UI项目,ABP默认提供两套UI:Blazor + Razor,新项目优先Blazor,老系统用Web层
七、test 测试目录
存放单元测试、集成测试项目,通常包含:Domain单元测试、Application应用服务测试、EF仓储测试
二、两种部署架构对应项目取舍
1. 一体化架构(单站点,开发简单)
使用:HttpApi.HostWithIds / Blazor.Server / Blazor.WebApp
- 认证、API、UI全部在一个站点,数据库本地访问,无跨服务调用
- 不需要独立
AuthServer、不需要Tiered后缀项目
2. Tiered 分层架构(分布式,生产推荐)
使用带 .Tiered 项目 + 独立 AuthServer + HttpApi.Host
拆分3个独立部署服务:
- AuthServer 身份认证中心
- HttpApi.Host 后端接口服务
- Blazor Tiered 前端站点
前端通过HttpApi.Client远程调用API,多服务分离,支持集群、分布式部署
三、项目依赖流转极简链路(分层调用顺序)
后端内部依赖
Domain.Shared ← Domain ← Application.Contracts ← Application ← HttpApi ← HttpApi.Host
前端调用链路
Blazor 项目 → HttpApi.Client(代理)→ 远程 HttpApi.Host 接口 → Application应用服务 → Domain领域层 → EF/Mongo数据库
四、红标 HttpApi.Client 核心作用总结
- 自动封装所有后端AppService的HTTP请求,强类型C#代理
- Blazor前端直接引用,不用手写HttpClient、不用重复定义DTO
- 自动携带JWT令牌、处理异常、统一请求拦截
- 分层架构必备,是前后端C#代码互通的契约桥梁
ABP vNext Tiered 分层架构完整架构图(文字结构化+层级流程图)
一、整体分层架构流程图(从上至下:客户端 → 认证中心 → API服务 → DDD业务层 → 数据层)
#mermaid-svg-o5AqG1tVXxtNjbfR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-o5AqG1tVXxtNjbfR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-o5AqG1tVXxtNjbfR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-o5AqG1tVXxtNjbfR .error-icon{fill:#552222;}#mermaid-svg-o5AqG1tVXxtNjbfR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-o5AqG1tVXxtNjbfR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-o5AqG1tVXxtNjbfR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-o5AqG1tVXxtNjbfR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-o5AqG1tVXxtNjbfR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-o5AqG1tVXxtNjbfR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-o5AqG1tVXxtNjbfR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-o5AqG1tVXxtNjbfR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-o5AqG1tVXxtNjbfR .marker.cross{stroke:#333333;}#mermaid-svg-o5AqG1tVXxtNjbfR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-o5AqG1tVXxtNjbfR p{margin:0;}#mermaid-svg-o5AqG1tVXxtNjbfR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-o5AqG1tVXxtNjbfR .cluster-label text{fill:#333;}#mermaid-svg-o5AqG1tVXxtNjbfR .cluster-label span{color:#333;}#mermaid-svg-o5AqG1tVXxtNjbfR .cluster-label span p{background-color:transparent;}#mermaid-svg-o5AqG1tVXxtNjbfR .label text,#mermaid-svg-o5AqG1tVXxtNjbfR span{fill:#333;color:#333;}#mermaid-svg-o5AqG1tVXxtNjbfR .node rect,#mermaid-svg-o5AqG1tVXxtNjbfR .node circle,#mermaid-svg-o5AqG1tVXxtNjbfR .node ellipse,#mermaid-svg-o5AqG1tVXxtNjbfR .node polygon,#mermaid-svg-o5AqG1tVXxtNjbfR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-o5AqG1tVXxtNjbfR .rough-node .label text,#mermaid-svg-o5AqG1tVXxtNjbfR .node .label text,#mermaid-svg-o5AqG1tVXxtNjbfR .image-shape .label,#mermaid-svg-o5AqG1tVXxtNjbfR .icon-shape .label{text-anchor:middle;}#mermaid-svg-o5AqG1tVXxtNjbfR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-o5AqG1tVXxtNjbfR .rough-node .label,#mermaid-svg-o5AqG1tVXxtNjbfR .node .label,#mermaid-svg-o5AqG1tVXxtNjbfR .image-shape .label,#mermaid-svg-o5AqG1tVXxtNjbfR .icon-shape .label{text-align:center;}#mermaid-svg-o5AqG1tVXxtNjbfR .node.clickable{cursor:pointer;}#mermaid-svg-o5AqG1tVXxtNjbfR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-o5AqG1tVXxtNjbfR .arrowheadPath{fill:#333333;}#mermaid-svg-o5AqG1tVXxtNjbfR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-o5AqG1tVXxtNjbfR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-o5AqG1tVXxtNjbfR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o5AqG1tVXxtNjbfR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-o5AqG1tVXxtNjbfR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o5AqG1tVXxtNjbfR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-o5AqG1tVXxtNjbfR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-o5AqG1tVXxtNjbfR .cluster text{fill:#333;}#mermaid-svg-o5AqG1tVXxtNjbfR .cluster span{color:#333;}#mermaid-svg-o5AqG1tVXxtNjbfR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-o5AqG1tVXxtNjbfR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-o5AqG1tVXxtNjbfR rect.text{fill:none;stroke-width:0;}#mermaid-svg-o5AqG1tVXxtNjbfR .icon-shape,#mermaid-svg-o5AqG1tVXxtNjbfR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o5AqG1tVXxtNjbfR .icon-shape p,#mermaid-svg-o5AqG1tVXxtNjbfR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-o5AqG1tVXxtNjbfR .icon-shape .label rect,#mermaid-svg-o5AqG1tVXxtNjbfR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o5AqG1tVXxtNjbfR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-o5AqG1tVXxtNjbfR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-o5AqG1tVXxtNjbfR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 持久层实现
DDD业务分层
HttpApi.Host 接口网关
独立认证服务 AuthServer
前端UI层
1.登录获取JWT
1.登录获取JWT
1.登录获取JWT
2.携带Token远程调用
2.携带Token远程调用
HTTP请求
实现
依赖仓储接口
依赖仓储接口
Blazor WebAssembly Tiered Client
Blazor Server Tiered
第三方客户端/小程序/Postman
AuthServer 身份中心
OpenIddict 登录/颁发JWT/第三方登录
HttpApi.Client 强类型代理
封装HttpClient、自动带Token、DTO契约
HttpApi 控制器层
转发HTTP请求到应用服务
Application 应用服务层
流程编排、事务、DTO映射
Application.Contracts 契约层
IAppService、输入输出DTO
Domain 领域层
聚合根、实体、领域服务、业务规则
Domain.Shared 共享层
枚举、常量、权限、本地化
EntityFrameworkCore EF仓储实现
DbContext、数据库迁移
MongoDB Mongo仓储实现
SQL Server/MySQL/MongoDB 数据库
DbMigrator 迁移工具
初始化库、种子数据、执行迁移脚本
二、按程序集依赖关系图(项目引用流向,底层→上层)
#mermaid-svg-xRgiIR4RWGzxwR3z{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xRgiIR4RWGzxwR3z .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xRgiIR4RWGzxwR3z .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xRgiIR4RWGzxwR3z .error-icon{fill:#552222;}#mermaid-svg-xRgiIR4RWGzxwR3z .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xRgiIR4RWGzxwR3z .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xRgiIR4RWGzxwR3z .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xRgiIR4RWGzxwR3z .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xRgiIR4RWGzxwR3z .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xRgiIR4RWGzxwR3z .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xRgiIR4RWGzxwR3z .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xRgiIR4RWGzxwR3z .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xRgiIR4RWGzxwR3z .marker.cross{stroke:#333333;}#mermaid-svg-xRgiIR4RWGzxwR3z svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xRgiIR4RWGzxwR3z p{margin:0;}#mermaid-svg-xRgiIR4RWGzxwR3z .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xRgiIR4RWGzxwR3z .cluster-label text{fill:#333;}#mermaid-svg-xRgiIR4RWGzxwR3z .cluster-label span{color:#333;}#mermaid-svg-xRgiIR4RWGzxwR3z .cluster-label span p{background-color:transparent;}#mermaid-svg-xRgiIR4RWGzxwR3z .label text,#mermaid-svg-xRgiIR4RWGzxwR3z span{fill:#333;color:#333;}#mermaid-svg-xRgiIR4RWGzxwR3z .node rect,#mermaid-svg-xRgiIR4RWGzxwR3z .node circle,#mermaid-svg-xRgiIR4RWGzxwR3z .node ellipse,#mermaid-svg-xRgiIR4RWGzxwR3z .node polygon,#mermaid-svg-xRgiIR4RWGzxwR3z .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xRgiIR4RWGzxwR3z .rough-node .label text,#mermaid-svg-xRgiIR4RWGzxwR3z .node .label text,#mermaid-svg-xRgiIR4RWGzxwR3z .image-shape .label,#mermaid-svg-xRgiIR4RWGzxwR3z .icon-shape .label{text-anchor:middle;}#mermaid-svg-xRgiIR4RWGzxwR3z .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xRgiIR4RWGzxwR3z .rough-node .label,#mermaid-svg-xRgiIR4RWGzxwR3z .node .label,#mermaid-svg-xRgiIR4RWGzxwR3z .image-shape .label,#mermaid-svg-xRgiIR4RWGzxwR3z .icon-shape .label{text-align:center;}#mermaid-svg-xRgiIR4RWGzxwR3z .node.clickable{cursor:pointer;}#mermaid-svg-xRgiIR4RWGzxwR3z .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xRgiIR4RWGzxwR3z .arrowheadPath{fill:#333333;}#mermaid-svg-xRgiIR4RWGzxwR3z .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xRgiIR4RWGzxwR3z .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xRgiIR4RWGzxwR3z .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xRgiIR4RWGzxwR3z .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xRgiIR4RWGzxwR3z .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xRgiIR4RWGzxwR3z .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xRgiIR4RWGzxwR3z .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xRgiIR4RWGzxwR3z .cluster text{fill:#333;}#mermaid-svg-xRgiIR4RWGzxwR3z .cluster span{color:#333;}#mermaid-svg-xRgiIR4RWGzxwR3z div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xRgiIR4RWGzxwR3z .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xRgiIR4RWGzxwR3z rect.text{fill:none;stroke-width:0;}#mermaid-svg-xRgiIR4RWGzxwR3z .icon-shape,#mermaid-svg-xRgiIR4RWGzxwR3z .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xRgiIR4RWGzxwR3z .icon-shape p,#mermaid-svg-xRgiIR4RWGzxwR3z .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xRgiIR4RWGzxwR3z .icon-shape .label rect,#mermaid-svg-xRgiIR4RWGzxwR3z .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xRgiIR4RWGzxwR3z .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xRgiIR4RWGzxwR3z .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xRgiIR4RWGzxwR3z :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Domain.Shared
Domain
Application.Contracts
Application
HttpApi
HttpApi.Host
EntityFrameworkCore
MongoDB
AuthServer
HttpApi.Client
Blazor.WebApp.Tiered
Blazor.Server.Tiered
Blazor共享层
三、分层职责拆解对照(对应你截图里所有项目)
1. 接入层(最外层,用户访问)
- Blazor 系列 Tiered 项目:前端界面,浏览器交互,远程调用后端API
- AuthServer:独立单点登录服务,签发JWT令牌,所有客户端统一认证入口
- HttpApi.Host:独立后端接口服务,提供RESTful接口
2. 通信契约层(前后端统一标准)
- HttpApi.Client(红标项目):基于Application.Contracts自动生成C#客户端代理,前端无需手写HTTP请求
- Application.Contracts:前后端数据交换标准(接口、DTO),是整个系统的"契约文档"
3. DDD核心业务四层(后端业务逻辑)
| 项目 | 层级 | 核心职责 |
|---|---|---|
| Domain.Shared | 共享层 | 全局常量、枚举、权限Key、多语言、基础异常,无业务实现 |
| Domain | 领域层(DDD核心) | 实体、聚合根、领域服务、核心业务规则、仓储接口 |
| Application.Contracts | 应用契约 | 应用服务接口、入参/出参DTO,对外暴露能力定义 |
| Application | 应用服务层 | 实现契约接口,事务、权限校验、流程编排、DTO转换 |
4. 数据持久层
- EntityFrameworkCore:EF Core实现Domain定义的仓储,数据库映射、迁移
- MongoDB:MongoDB仓储实现,NoSQL数据库适配
- DbMigrator:控制台工具,单独执行数据库迁移、初始化种子数据(租户、管理员、权限)
5. 辅助/UI兼容项目
- Blazor(无Tiered):一体化Blazor(前后端同进程,本地调用应用服务,不通过HttpApi.Client)
- Web / Web.Host:传统Razor MVC页面UI(老版UI方案)
- test:单元/集成测试项目
四、一体化架构 vs Tiered分层架构 差异补充
- 一体化架构(单站点部署)
- 无独立AuthServer、无Tiered前端项目、无需HttpApi.Client远程调用
- UI、API、认证全部在一个Host内,直接本地引用Application层,调用链路短,适合小型项目
- Tiered分层架构(分布式生产架构,你截图里的模板)
- 拆分3个独立服务:Auth认证中心、HttpApi接口服务、Blazor前端站点
- 前端通过
HttpApi.Client走HTTP远程调用API,服务可独立集群、扩容、分库部署,中大型企业系统标准方案
五、一次完整请求全链路(Tiered分层场景)
- 用户打开Blazor前端 → 跳转AuthServer登录,输入账号密码获取JWT令牌
- 前端点击业务按钮 → 通过
HttpApi.Client携带Token发起HTTP请求到HttpApi.Host - HttpApi控制器接收请求,调用对应Application应用服务
- Application层校验权限、组装业务流程,调用Domain领域服务执行核心业务规则
- Domain通过EF/Mongo仓储操作数据库,完成增删改查
- 数据逐层返回,经HttpApi.Client序列化展示到Blazor页面