分层模型与依赖方向
应用内部分层
rust-webx 推荐的业务应用分层:
┌─────────────────────────────────────────┐
│ main.rs / startup.rs 启动与组合根 │
├─────────────────────────────────────────┤
│ handlers/ 应用层(履约) │
│ IRequestHandler 实现 │
│ I…Service 实现 │
├─────────────────────────────────────────┤
│ domain/ 持久化与实体层 │
├─────────────────────────────────────────┤
│ contracts/ 接口契约层 │
│ Request/Response DTO │
│ enum / I…Service trait │
└─────────────────────────────────────────┘
**不设**独立的 `services/` 层。业务接口在 contracts,实现在 handlers。
各层职责
contracts — 契约层
**拥有**:API 路由声明、Request/Response DTO、共享 enum、`I…Service` trait、授权元数据
// contracts/auth.rs
pub trait IAuthService: Send + Sync {
fn login(&self, email: &str, password: &str) -> Result<AuthResponse, String>;
}
#[post("/api/auth/login")]
impl IRequest<AuthResponse> for LoginRequest {}
- 不含业务实现 - **仅依赖框架**(`webx`),**禁止依赖 domain** - 是对外 API 与业务抽象的「说明书」
handlers — 应用层
**拥有**:`IRequestHandler` 实现、`I…Service` 具体实现、用例编排
// handlers/auth.rs
#[inject]
pub struct AuthService { ... }
impl IAuthService for AuthService { ... }
#[derive(Inject)]
pub struct LoginHandler {
auth: Arc<dyn IAuthService>,
}
#[handler(inject)]
#[async_trait]
impl IRequestHandler<LoginRequest, AuthResponse> for LoginHandler { ... }
- 薄 Handler:参数传递、`Error` 映射 - 厚 Service 实现:业务规则、domain 访问 - Handler 只依赖 `Arc<dyn I…Service>`
domain — 领域模型层
**拥有**:实体、值对象、数据库迁移、EF 配置
// domain/user.rs
use crate::contracts::auth::UserRole;
pub struct UserEntity {
pub role: UserRole,
// ...
}
- 最稳定的一层 - **可以**引用 contracts 复用枚举或 model - 不依赖框架类型(除 `serde`)
main.rs / startup.rs — 组合根
**拥有**:Host 配置、`bootstrap` 基础设施注册、`IHostedService`
- 唯一允许手动注册 `DbContext`、`AppPaths` 等框架外类型的地方 - 业务 Handler / Service 由 `#[inject]` 自动收集,**不在 main 手动注册**
appsettings.json
框架运行时配置,与 ASP.NET Core 同名约定。
依赖方向
framework (webx)
↑
contracts ←── domain(可复用 contracts 类型)
↑
handlers ──→ domain
**禁止**:
- contracts → domain / handlers - domain → handlers - handlers 依赖具体 Service 类型(应使用 `Arc<dyn I…Service>`)
Docbit 实例(目标结构)
docbit/src/
├── contracts/ # LoginRequest, IBlogService trait, BlogPostSummary DTO, ...
├── handlers/ # LoginHandler, BlogService (impl IBlogService), ...
├── domain/ # UserEntity, migrations/
├── startup.rs # DbInitService (IHostedService)
└── main.rs # Host::builder() 组合根
> **迁移说明**:早期 Docbit 将 `I…Service` 放在 `services/`、contracts 引用 domain 类型,与本文规范不符。当前 Docbit 已按 contracts / handlers / domain 三层重构。
小结
分层是**职责边界**:contracts 定义「对外承诺什么」,handlers 定义「如何履约」,domain 定义「数据是什么」。面向接口,关注契约,不关注实现。
下一节:[编译时扫描机制](compile-time-scan.md)