如何为应用程序命令公开强类型ID且避免API层引用领域模型
我在领域模型(Domain Model)中使用强类型ID(Strongly Typed Ids),这类ID例如ProductId、CustomerId等,均在领域模型中声明。
我的问题是如何将这些ID暴露给应用层(Application Layer)的调用方。目前API控制器会创建Command发送给应用层,这些Command需要用到ID,我当前在Command对象中使用基础类型Guid,调用领域模型方法时再转换为强类型ID。
我希望将强类型ID的类型校验能力延伸到API控制器和应用层的通信过程中,但又不想让API控制器引用当前声明了强类型ID的领域模型。
我目前想到两个方案,但都不够理想:
- 在应用层声明一套相似的强类型ID,但调用领域方法前需要在应用层强类型ID和领域层强类型ID之间做转换。
- 将强类型ID的声明迁移到API和领域模型都可引用的公共模块中,但这会导致领域模型依赖泄露到API控制器,领域模型的调整可能影响API层,不符合预期。
优化解决方案
方案1:拆分独立的强类型ID契约模块
把强类型ID的定义从领域层拆分到一个无任何业务依赖的公共契约模块中,这个模块仅包含ID的基础值对象逻辑:值相等判断、格式校验、基础转换方法,不包含任何领域业务规则。
- 领域层引用这个契约模块使用强类型ID
- API层和应用层也仅引用这个纯契约模块,不会接触到领域层的其他业务逻辑
这种方式完全避免了领域逻辑泄露,也不需要重复编写多套强类型ID,后续ID的基础规则调整只需要修改契约模块一处即可,仅当ID的定义发生突破性变更时才会影响上下游,符合开闭原则。
方案2:API层增加前置校验等效替代强类型校验能力
如果你不想额外拆分模块,也可以保留现有Command中用基础类型Guid的实现,仅在API层增加自定义校验属性覆盖强类型ID的校验逻辑:
- 给Command中的ID字段加自定义校验Attribute,比如
[ProductIdValidation],在API模型绑定阶段就完成和领域层强类型ID一致的规则校验 - 校验通过后的基础类型值传入应用层,转换为领域层强类型ID时不会再出现格式错误
这种方式不需要修改现有分层依赖,也能达到和强类型ID一致的提前校验效果,避免无效请求进入应用层和领域层。
方案3:用源生成器自动生成多套强类型ID和转换逻辑
如果你的强类型ID规则经常变化,不想维护公共契约,可以用C#源生成器,统一维护ID的规则配置,自动为应用层、领域层生成对应的强类型ID定义,以及两层之间的隐式转换代码。
- 你只需要维护一份ID列表(比如ProductId、CustomerId)和基础规则
- 源生成器自动在应用层、领域层生成对应强类型ID的代码,以及互相转换的扩展方法
这种方式既保证了两层的强类型ID完全解耦,也不需要手动编写重复代码和转换逻辑,后续修改规则只需要调整配置即可。
内容的提问来源于stack exchange,提问作者Neil W
相关产品推荐
相关产品推荐

