C# 依赖注入:具有多个依赖项的单个类(WCF服务)(数据库存储库)如何处理?

C# 依赖注入:具有多个依赖项的单个类(WCF服务)(数据库存储库)如何处理?,c#,dependency-injection,C#,Dependency Injection,我读过马克·希曼的一本书,这本书使我对许多事情有了新的认识。但问题仍然很少。以下是其中之一: 假设我们有一个WCF服务,它公开了用于处理某些数据库的API: public class MyService : IMyService { private ITableARepository _reposA; private ITableARepository _reposB; //.... public IEnumerable<EntityA> GetAE

我读过马克·希曼的一本书,这本书使我对许多事情有了新的认识。但问题仍然很少。以下是其中之一:

假设我们有一个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())
    }

    //...
}
公共类MyService:IMyService
{
私有信息存储库_reposA;
私人资讯科技资料库(reposB);
//....
公共IEnumerable GetAEntities()
{
return _reposA.GetAll().Select(x=>x.ToDTO())
}
公共IEnumerable getbenties()
{
返回_reposB.GetAll()。选择(x=>x.ToDTO())
}
//...
}
服务依赖的存储库可能有几十个。有些方法使用一种,有些方法使用另一种,有些方法使用很少的存储库

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

我看到的选择:

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

    我假设答案应该根据服务实例上下文模式而有所不同(可能是单实例时,构造函数注入就可以了;对于PerCall,如果忽略上述警告,选项3看起来最好;对于perSession,一切都取决于会话生存期:是更接近单实例还是PerCall)

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

    有人能解释一下这个案件应该如何正确解决吗

    创建一个包含数十个参数的大型构造函数

    您不应该创建具有大量构造函数参数的类。这就是代码的味道。拥有具有大量参数的构造函数表明这样的类做得太多:违反了。这导致代码很难维护和扩展

    另外,这对性能极为不利,因为每个未使用的存储库都是对资源的浪费

    你量过这个了吗?构造函数参数的数量主要与应用程序的性能无关。这不应导致任何明显的性能差异。如果是这样的话,那么现在是时候看看构造函数所做的工作量了(因为),或者如果构造函数很简单的话,是时候切换到更快的DI容器了。创建一组服务类通常应该非常快

    即使它不使用单独的数据库连接

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

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

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

    由于调用方无法确定需要哪些属性,所以需要注入所有属性,这使得性能与构造函数注入相当,正如我所说的,这根本不应该是一个问题

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

    您可以注入一个存储库提供者,而不是注入一个存储库工厂,这是一种更为人所知的模式。工作单元可以访问存储库

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

    不,因为您不应该使用WCF“单一”模式。在大多数情况下,您注入到WCF服务中的依赖项不是线程安全的,并且不应超过单个请求。将它们注入到单例WCF服务中会导致错误,这是不好的,因为它会导致各种并发错误

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

  • 将它们分成多个较小的类,或
  • 将功能移出它们并应用到模式中,如和模式

  • 你错了。无论是从性能还是参数数量来看@WiktorZychla,都是好的参数。虽然如果我们需要PerCall实例上下文模式,并遵循应该尽快关闭SQL连接的建议,我们最终会在每次需要时创建几十个新的存储库。我曾经看到一个数据库,里面有2个