Domain层出现任何PackageReference即违反Clean Architecture硬性契约,因其破坏“内层不依赖外层”原则;Domain.csproj仅允许<TargetFramework>,禁用所有<PackageReference>及框架特性如[JsonIgnore]、[Key]等。

Domain 层只要出现一个 PackageReference,整个 Clean Architecture 就已经失效。 这不是风格问题,是架构契约的硬性断裂点——后续所有分层、DI、测试都会在某个环节悄无声息地崩坏。
Domain 项目里为什么连 System.Text.Json 都不能引用
因为 System.Text.Json 是基础设施细节,它绑定的是序列化行为,而 Domain 的职责是定义“产品有 SKU、有库存量”这类业务事实,不关心怎么转成 JSON。一旦你在 Product.cs 里加了 [JsonIgnore] 或用 JsonSerializerOptions 做配置,就等于把表现层逻辑提前注入到核心契约中。
- 检查方式:打开
Domain.csproj,只允许存在<TargetFramework>net6.0</TargetFramework>,绝不能有<PackageReference>标签 - 实体类中禁止出现任何特性:
[Key]、[Required]、[StringLength]、[JsonPropertyName] - 值对象必须用
public readonly struct或私有构造 + 工厂方法,比如Money不能有public decimal Amount { get; set; }
Application 层写 CreateProductCommandHandler 时最容易踩的三个坑
它看起来只是个“调用链”,但实际是业务逻辑边界的守门人。多数人在这里把架构污染成“技术搬运工”。
- 别在 Handler 里调用
JsonSerializer.Serialize()或Mapper.Map<T>()—— DTO 转换属于 Presentation 或 Infrastructure 层职责 - 所有输入输出必须是 Application 自己定义的类型,例如
CreateProductCommand和CreateProductResponse,和 Domain 的Product实体完全无关 - 事务控制只暴露
IUnitOfWork.CommitAsync()接口,具体实现(如_context.SaveChangesAsync())必须封装在 Infrastructure 中
Program.cs 中注入 Infrastructure 实现时的关键约束
这是整个 Clean Architecture 的“唯一胶水点”,也是最常漏检的破口。这里写错,前面所有分层都白搭。
- 只能注册接口与实现的映射,例如
services.AddScoped<IProductRepository, SqlProductRepository>(),绝不能注册SqlProductRepository本身供其他层直接 new 或依赖 - 禁止在
Program.cs里出现new DbContextOptionsBuilder()或new HttpClient()这类具体构造逻辑 —— 它们应由对应工厂或配置封装 - 所有跨层依赖必须通过构造函数注入,且参数类型只能是 Domain 或 Application 中定义的接口(如
IProductDomainService),不能是DbContext或HttpClient
真正难的不是建好四个文件夹,而是每次添加新 NuGet 包、写新特性、加新验证逻辑时,都下意识问一句:这个东西,Domain 层能不能不依赖它还能编译通过、单元测试还能跑?问多了,架构才不会漏气。


















