基于DDD模型构建C# .NET 8四层架构的技术问询
DDD四层架构实践问题解答
问题1:应用层服务接口的放置位置
不是必须把IUserApplicationService放在领域层,完全可以放在应用层。
早期部分DDD示例会将各层接口集中在领域层,核心是为了践行依赖倒置原则,但这并非强制规范。应用层服务的接口本身是应用层对外暴露的契约,属于应用层的职责范畴,放在对应层级更贴合“关注点分离”的设计思路:
- 表现层直接依赖应用层接口,依赖关系更清晰;
- 应用层接口的变更仅影响自身和调用方,不会污染领域层的核心逻辑;
- 领域层只需专注于核心业务规则、领域对象及领域相关契约(如仓储接口、领域服务接口)。
只要保证领域层不依赖应用层,就不会破坏分层的依赖规则。
问题2:活跃用户查询的方案选择
直接在仓储层使用select * from user where active = 1不违反DDD原则,反而更合理,关键要区分业务规则定义和查询实现细节。
核心逻辑:
- 业务规则归属:“活跃用户”的定义(比如
active = 1代表活跃)属于领域层的业务规则,应该由领域层统一约定(例如在User实体中定义IsActive属性,或在领域服务中明确规则)。 - 查询实现优化:仓储的职责就是高效获取符合业务规则的数据,利用数据库的过滤能力是合理的性能优化——DDD从不要求牺牲性能来换取纯内存逻辑。
正确做法:
- 在领域层的
IUserRepository接口中定义GetActiveUsers()方法,明确这是符合领域规则的查询契约; - 在基础设施层的Dapper实现中,用带
where active = 1的SQL来实现该方法,既遵循依赖倒置(领域定义接口,基础设施实现),又利用了数据库的性能优势。
百万级用户量下仍拉取全量数据过滤,属于不必要的性能浪费,这种场景下必须在数据库层面做过滤,这与DDD原则并无冲突。
问题3:Worker Service的层级归属
Worker Service属于表现层。
表现层的核心职责是作为应用的入口/对外交互层,负责触发应用层的业务逻辑,并非必须依赖用户输入:
- 例如API、MVC项目是处理用户HTTP请求的表现层,Worker Service则是处理定时任务、消息队列事件的表现层;
- 应用层的职责是封装业务流程、协调领域对象与仓储,本身不负责启动或监听外部触发事件。
将Worker Service归为表现层,符合分层的职责划分:它作为启动项目,负责初始化应用、触发应用层服务,与其他表现层项目的角色一致。
内容的提问来源于stack exchange,提问作者Sil_2
相关产品推荐
相关产品推荐

