空解决方案是唯一可控起点,因直接建多项目结构易致路径错乱、启动项错位及引用失效;Domain层须用.NET Standard或统一TargetFramework,禁用基础设施引用,Application层仅通过接口依赖Infrastructure,配置只由主项目加载。
直接用“新建解决方案”模板建多项目结构,九成会在调试、配置加载、引用解析上出问题——不是代码写错了,是根目录和项目关系从一开始就没对齐。
空解决方案才是唯一可控起点
Visual Studio 里点“新建项目”时勾选“创建解决方案目录”,看似一步到位,实则埋下路径错乱、启动项目错位、类库无法被识别的隐患。尤其是后续要加测试项目、CLI 工具或跨平台类库时,.sln 文件里项目路径会突然变成相对路径错误或硬编码绝对路径。
正确做法:打开 VS → 新建项目 → 搜索
(位置在“已安装 → 其他项目类型 → Visual Studio 解决方案”)→ 命名后只生成一个
文件
再右键解决方案 → 添加 → 新建项目 → 逐个添加主项目(如
或
)、
、
、
等
第一个添加的项目默认为启动项目;如需切换,右键目标项目 →
设为启动项目
Domain 层必须是纯 .NET Standard 或统一 TargetFramework
Clean Architecture 要求
层不依赖任何框架、数据库或 I/O 组件,但它仍得被其他层引用。一旦
项目用了
这类带平台后缀的
,层哪怕也是 net8.0,也会因平台不匹配导致编译报错或不生效。
新建
项目时,务必选
(兼容性最强)或
(若全栈都锁定 .NET 6+)
检查其
中是否为
,而非
或
项目中禁止出现
、
等任何基础设施相关引用
Application 层不能直接 new Infrastructure 实现类
Clean Architecture 的核心约束是“依赖倒置”:高层模块(
)不应依赖低层模块(
),而应通过接口(定义在
或
中)与其实现解耦。否则,单元测试时无法 mock 数据访问,且违反了“领域逻辑不可知技术细节”的原则。
C知道
CSDN推出的一款AI技术问答工具
下载
层定义接口,例如
,放在
下
层实现该接口,例如
,并只在主项目(如
)的
中注册:
层代码中只能构造函数注入
,绝不可写
若误在
中引用
项目,VS 会提示“项目引用循环”或编译失败
appsettings.json 只在主项目加载,Infrastructure 不读配置文件
把连接字符串写进
项目的
是无效的——.NET Core / .NET 6+ 只加载启动项目的配置文件。
层若硬编码读取,运行时必抛
或
。
所有配置项(数据库连接串、Redis 地址、第三方 API Key)必须放在主项目(如
)的
中
层通过构造函数接收配置值,例如:
主项目注册服务时传入:
避免在
中使用
(.NET Framework 风格)或
(重复构建配置树,性能差且易错)
最常被跳过的环节是检查每个项目的
是否真正对齐——不是“看着都是 net6.0”,而是打开每个
文件确认标签内容完全一致;另一个隐形陷阱是
层悄悄引用了
,表面能编译,但一跑单元测试就崩。架构不是图画画得漂亮就行,是每个
和每行
都得经得起反向依赖检查。
Blank Solution.slnWebApiConsoleAppDomainApplicationInfrastructureDomainDomainnet8.0-windowsApplicationusing Domain;DomainClass Library (.NET Standard 2.1)Class Library (.NET 6.0).csprojnet6.0 net6.0-windowsnet8.0-androidDomainMicrosoft.Extensions.DependencyInjectionSystem.Data.SqlClientApplicationInfrastructureApplicationDomainApplicationIUserRepositoryApplication/Interfaces/InfrastructureSqlUserRepositoryWebApiProgram.csservices.AddScoped() ApplicationIUserRepositorynew SqlUserRepository(...)ApplicationInfrastructureInfrastructureappsettings.jsonInfrastructureNullReferenceExceptionConfigurationErrorsExceptionWebApiappsettings.jsonInfrastructurepublic SqlUserRepository(string connectionString)services.AddScoped(sp => new SqlUserRepository(Configuration.GetConnectionString("Default"))) InfrastructureConfigurationManagernew ConfigurationBuilder()TargetFramework.csprojDomainMicrosoft.AspNetCore.Http.csprojusing