.NET分层项目中DI与仓储-服务模式的问题及正确实现咨询
.NET 7分层项目依赖注入与层访问问题解答
问题1:为什么Web API能够访问仓储层?
这是因为.NET的项目引用默认是传递性的:Web API直接引用了服务层,而服务层又引用了仓储层,所以仓储层的程序集会被间接传递给Web API项目。VS会自动检测到传递过来的程序集中的类型(包括仓储层的扩展方法),因此可以添加using MyApp.Repository;并调用对应的方法,即使Web API没有直接添加仓储层的项目引用。
问题2:如何阻止这种跨层访问的情况?
可以通过以下几种方式实现:
- 设置私有项目引用:在服务层引用仓储层时,修改项目引用的属性,将
PrivateAssets设置为all。这样仓储层的程序集不会被传递到Web API项目,Web API就无法访问仓储层的任何类型。 - 拆分接口与实现:把仓储层的接口(如
IMyRepository)单独提取到一个独立的类库项目(比如MyApp.Repository.Contracts)。服务层只引用这个接口项目,仓储层的实现项目引用接口项目。Web API仅引用服务层,无法接触到仓储层的实现类和扩展方法。 - 使用internal访问修饰符:将仓储层的扩展方法、仓储实现类都标记为
internal(默认就是internal,除非显式设为public),这样只有仓储层程序集内部可以访问,Web API即使拿到传递引用,也无法调用这些类型。
问题3:仓储类的正确DI实现方式是什么?是否应放弃在仓储层配置MongoDB客户端,转而在服务层编写统一的扩展方法?
两种方案都可行,取决于项目的分层复杂度和独立性需求:
方案一:保留仓储层的独立配置(推荐,保持分层职责)
优化现有实现,避免Web API直接操作仓储层:
- 将仓储层的
AddRepository扩展方法改为internal,限制仅内部访问。 - 在服务层的扩展方法中统一调用仓储层的配置,同时把连接字符串参数传递进去:
// 服务层扩展方法修改 namespace MyApp.Service { public static class ServiceCollectionExtensions { public static IServiceCollection AddServices(this IServiceCollection services, string mongoDbConnectionString) { // 内部调用仓储层的配置(服务层引用仓储层,且方法为internal,仅服务层可调用) services.AddRepository(mongoDbConnectionString); services.AddSingleton<IMyService, MyService>(); return services; } } }
- Web API的Program.cs只需要调用服务层的统一方法:
var mongoDbConnectionString = builder.Configuration.GetConnectionString("MongoDB"); builder.Services.AddServices(mongoDbConnectionString);
- 同时给服务层引用仓储层的项目设置
PrivateAssets="all",彻底阻断Web API对仓储层的访问路径。
方案二:统一在服务层配置(适合简单项目)
如果项目分层不需要仓储层具备独立配置能力,可以把MongoDB客户端和仓储的注入逻辑移到服务层的扩展方法中。这种方式简化了配置,但会降低仓储层的独立性,当仓储层需要调整配置时,必须修改服务层代码。
内容的提问来源于stack exchange,提问作者Asheq Reza
相关产品推荐
相关产品推荐

