在ASP.NET Core的Clean Architecture与Mediator模式下,Application层复杂可复用业务逻辑的放置位置咨询
嗨,Blake,你的困惑其实挺常见的——很多人从传统Service模式切换到CQRS+Mediator的Clean架构时,都会纠结业务逻辑的归属问题。先给你吃颗定心丸:你的思路完全没问题,在Application层创建Services文件夹存放ProductService这类封装复杂复用逻辑的服务是非常合理的做法!
下面给你拆解下具体的逻辑和可选方案:
为什么适合放在Application层的Services里?
Clean Architecture的核心是依赖方向:Domain层是最核心的业务规则层,Application层依赖Domain层,Infrastructure层依赖Application层。你的ProductService封装的是跨多个Command/Query的复用业务逻辑,它不属于单一的请求处理流程,也不属于Domain层中与实体强绑定的核心规则(比如Product.CalculateMemberDiscount()这种属于实体自身的行为,应该放在Domain层的实体类里)。把这类跨用例的复用逻辑放在Application层的Services中,既符合依赖规则,又能让你的Command/Query Handler保持简洁专注,只负责请求的协调和响应。Service里该返回Domain实体还是DTO?
你想得很对,这类Service应该返回Domain实体。因为Application层的核心职责是协调Domain逻辑与外部资源(比如Repository),而DTO是Presentation层和Application层之间的数据传输契约,属于更外层的交互概念。Handler拿到Domain实体后,再根据需要映射成DTO返回给Presentation层,这样能严格区分各层职责:Service专注业务逻辑实现,Handler专注CQRS的请求响应流转,DTO只在边界层做数据传输。有没有其他可选方案?
当然,如果你觉得Services文件夹有点“回到老模式”的感觉,也可以根据逻辑类型选择其他方式:- Domain层的Domain Service:如果你的复用逻辑是涉及多个Domain实体的核心业务规则(比如
OrderService.CalculateOrderTotal(Order, List<Product>)),那放在Domain层的Domain Service更合适——因为这属于业务核心规则,不依赖外部基础设施。但如果逻辑需要调用Repository或其他外部依赖,还是放在Application层的Service里更稳妥,毕竟Domain层不能依赖外部资源。 - Application层的Helper/Utility类:如果只是纯计算类的复用逻辑(比如价格换算、日期校验),可以做成静态Helper类,但要注意这类类只做纯工具性计算,不能包含业务规则。
- Domain层的Domain Service:如果你的复用逻辑是涉及多个Domain实体的核心业务规则(比如
最后给你个实践小建议:不管用哪种方式,都要尽量让你的Command/Query Handler保持“薄”——Handler只负责接收请求、调用对应的Service/Domain逻辑、处理实体到DTO的映射、返回结果,不要在Handler里写复杂的业务逻辑,这样代码会更易维护、易测试。
备注:内容来源于stack exchange,提问作者Blake Rivell

