【发布时间】:2014-08-11 19:24:11
【问题描述】:
我读过 Mark Seemann 的书"Dependency injection in .NET",它让我对许多事情大开眼界。但还剩下几个问题。这是其中之一:
假设我们有一个 WCF 服务公开 API 用于处理某些数据库:
public class MyService : IMyService
{
private ITableARepository _reposA;
private ITableARepository _reposB;
//....
public IEnumerable<EntityA> GetAEntities()
{
return _reposA.GetAll().Select(x=>x.ToDTO())
}
public IEnumerable<EntityB> GetBEntities()
{
return _reposB.GetAll().Select(x=>x.ToDTO())
}
//...
}
可能有几十个服务依赖的存储库。有些方法使用一种,有些方法使用另一种,有些方法使用很少的存储库。
我的问题是如何正确地将存储库依赖项注入到服务中?
我看到的选项:
- 构造函数注入。创建一个带有几十个参数的巨大构造函数。易于使用,但难以管理参数列表。此外,这对性能非常不利,因为每个未使用的存储库都是浪费资源,即使它不使用单独的数据库连接。
- 属性注入。优化性能,但使用变得不明显。服务的创建者应该如何知道要为特定方法调用初始化哪些属性?此外,这个创建者应该对每个方法调用都是通用的,并且位于组合根中。所以那里的逻辑变得非常复杂且容易出错。
- 有点不标准(书中没有描述)的方法:创建一个存储库工厂并依赖它而不是具体的存储库。但是这本书说,工厂经常被错误地用作克服问题的一种方法,这些问题可以通过正确使用 DI 得到更好的解决。所以这种方法对我来说看起来很可疑(同时实现了性能和透明度目标)。
或者这种关系 1 与许多依赖关系是否存在概念问题?
我认为答案应该根据服务实例上下文模式而有所不同(可能是单实例时,构造函数注入就可以了;对于 PerCall 选项 3,如果忽略上述警告看起来最好;对于 perSession,一切都取决于会话生命周期:无论是更接近单实例还是 PerCall)。
如果它真的依赖于实例上下文模式,那么就很难对其进行更改,因为更改需要对代码进行大量更改(从构造函数注入转移到属性注入或存储库工厂)。但是 WCF 服务的整个概念确保更改实例上下文模式很简单(而且我需要更改它的可能性不大)。这让我对 DI 和 WCF 的组合更加困惑。
谁能解释这个案例应该如何正确解决?
【问题讨论】:
-
你错了 1. 在性能和参数数量方面blog.ploeh.dk/2010/01/20/…
-
@WiktorZychla,很好的论据。尽管如果我们需要 PerCall 实例上下文模式,并遵循应尽快关闭 SQL 连接的建议,我们最终会在每次需要时创建数十个新存储库。我曾经看到一个有 200 多个表的数据库。幸运的是,存储库的创建成本并不高。但是从设计的角度来看是不是很奇怪?
-
不是,我不在乎创建了多少实例,只要你正确关闭所有打开的连接。