依赖注入:单个类(WCF服务)有多个依赖(DB存储库)如何处理?

时间:2014-07-07 16:25:18

标签: c# dependency-injection

我已经读过马克·西曼(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())
    }

    //...
}

可能有数十个存储库服务依赖。有些方法使用一种方法,有些方法使用另一种方法,有些方法使用的是少量存储库。

我的问题是如何正确组织存储库依赖项注入服务

我看到的选项:

  1. 构造函数注入。用几十个参数创建一个巨大的构造函数。易于使用,但很难管理参数列表。此外,它对性能的影响非常大,因为即使它没有使用单独的数据库连接,每个未使用的存储库也会浪费资源。
  2. 物业注入。优化性能,但使用率变得不明显。服务的创建者应该如何知道为特定方法调用初始化哪些属性?此外,此创建者应该对每个方法调用都是通用的,并且位于组合根中。因此,那里的逻辑变得非常复杂且容易出错。
  3. 有些非标准(未在书中描述)方法:创建存储库工厂并依赖它而不是具体的存储库。但是这本书说工厂经常被错误地用作克服问题的一种方法,这些问题可以通过适当的DI使用得到更好的解决。所以这种方法对我来说很可疑(同时实现了绩效和透明度目标)。
  4. 或者这个关系存在一个概念上的问题1到多个依赖关系?

    我认为答案应该根据服务实例上下文模式而有所不同(可能是它的单个实例,构造函数注入很好;对于PerCall选项3看起来最好忽略上面的警告;对于perSession,一切都取决于会话生命周期:它是否更接近单实例或PerCall。

    如果它确实依赖于实例上下文模式,那么就很难对其进行更改,因为更改需要对代码进行大的更改(从构造函数注入转移到属性注入或存储库工厂)。但是WCF服务的整个概念确保了更改实例上下文模式很简单(并且我不太可能需要更改它)。这让我对DI和WCF组合更加困惑。

    有人能解释一下如何正确解决这个案子吗?

1 个答案:

答案 0 :(得分:5)

  
    

使用几十个参数创建一个巨大的构造函数

  

您不应该创建具有大量构造函数参数的类。这是constructor over-injection代码气味。拥有大量参数的构造函数表明这样的类太多了:违反了Single Responsibility Principle。这导致代码难以维护和扩展。

  
    

同样,它对性能非常不利,因为每个未使用的存储库都是浪费资源

  
你测量过这个吗?构造函数参数的数量应该主要是对应用程序的性能不敬。这不应该导致任何明显的性能差异。如果确实如此,那么现在应该看看构造函数所做的工作量(自injection constructors should be simple)或时间切换到更快的DI容器(如果构造函数很简单)。创建一堆服务类通常应该非常快。

  
    

即使它没有使用单独的数据库连接。

  

构造函数不应该首先打开连接。再说一次:它们应该是simple

  
    

物业注入。优化性能     该服务的创建者应该如何知道为特定方法调用初始化哪些属性

  

调用者无法可靠地确定需要哪些依赖项,因为通常只需要构造函数参数。需要属性会导致temporal coupling,并且您将失去编译时支持。

由于调用者无法确定需要哪些属性,因此需要注入所有属性,这使得性能与构造函数注入等效,我说 - 根本不应该成为问题。

  
    

有些非标准(未在书中描述)方法:创建存储库工厂并依赖它而不是具体的存储库。

  

您可以注入存储库提供程序,而不是注入存储库工厂,这种模式更为人所知的是Unit of Work pattern。工作单元可以访问存储库。

  
    

我认为答案应根据服务实例上下文模式而有所不同

  

不,因为你永远不应该使用WCF&#39; Single&#39;模式。在大多数情况下,您注入WCF服务的依赖项不是线程安全的,不应该超过单个请求。将它们注入单个WCF服务会导致Captive Dependencies,这很糟糕,因为它会导致各种并发错误。

这里的核心问题似乎是您的WCF服务类很大并且违反了单一责任原则,导致它们难以创建,维护和测试。通过以下方式修复此违规行为:

  1. 将它们分成多个较小的类,或
  2. 将功能移出aggregate services并应用command/handlerquery/handler模式等模式。