You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET依赖管理:领域类应单独存于程序集吗?求社区最佳实践

最佳实践:分离领域层与基础设施层,辅以InternalsVisibleTo或DDD设计技巧

这是个非常经典的领域驱动设计(DDD)架构问题,社区里已经形成了比较统一的最佳实践,我来帮你梳理清楚:

首先,保持Core.dll(领域层)和Application.dll(基础设施/仓储层)分离是更推荐的方案,这完全贴合DDD中"领域模型独立于外部基础设施"的核心原则——你提到的"引用Core.dll时无需依赖SqlClient等库"这个优势,其实就是这种架构最核心的价值之一:领域层可以被独立复用、测试,甚至在不同的基础设施实现(比如从SQL Server换成MongoDB)中直接迁移,不会被具体的数据库依赖绑定。

接下来解决你头疼的访问修饰符问题,这里有两个常用的社区方案:

方案1:用InternalsVisibleTo特性实现精准隔离

这是最直接的解决方案。在Core.dll的项目配置里(或者AssemblyInfo.cs文件中)添加如下代码:

[assembly: InternalsVisibleTo("Application")]

这样Core.dll中标记为internal的方法、字段或者属性,就只能被Application.dll中的仓储类访问,而Web.dll(或其他引用Core.dll的外部项目)完全看不到这些内部成员,完美实现了你想要的"仓储能访问、Web层不能"的权限控制。

小提示:如果你的程序集使用了强签名,记得在InternalsVisibleTo中指定Application.dll的强名称公钥,避免出现权限验证问题。

方案2:遵循DDD仓储设计原则,从根源减少内部访问需求

另一种更贴合DDD思想的方式是调整仓储的设计:

  • 在Core.dll中定义仓储的接口(比如IOrderRepository),接口只暴露领域层需要的业务方法,比如Task<Order> GetByIdAsync(Guid id)
  • 领域对象的核心逻辑依然保持private或internal,仓储的具体实现(Application.dll中的SqlOrderRepository)通过接口与领域对象交互,不需要直接访问领域对象的内部细节
  • 如果确实需要仓储触发领域对象的某些内部逻辑,可以考虑把这些逻辑封装成internal方法配合InternalsVisibleTo,或者设计成Core.dll中的"领域服务",让仓储通过调用领域服务来完成操作,进一步明确边界

关于合并程序集的思路

合并Core和Application.dll虽然能快速解决访问修饰符的问题,但会带来几个长期的弊端:

  • 领域层失去了独立性:一旦基础设施层引入新的依赖(比如换ORM框架、加缓存库),领域层也会被牵连,违背了"领域模型不依赖外部库"的初衷
  • 复用性下降:如果其他项目只需要领域模型,不得不连带引用整个合并后的程序集,包括里面的SqlClient等不必要的依赖
  • 边界模糊:业务逻辑和数据访问代码混在一起,长期维护容易导致职责不清,代码变得难以梳理和测试

总结

优先选择分离Core和Application.dll的架构,配合InternalsVisibleTo解决访问修饰符的痛点,同时遵循DDD的仓储设计原则,这样既能保持领域层的纯粹性和复用性,又能实现层与层之间的合理隔离,是社区公认的最佳实践。

内容的提问来源于stack exchange,提问作者mfreedm52

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:07:12