一般的IoC实践 - 服务相互依赖是错误的吗?

Ada*_*dam 7 c# asp.net-mvc dependency-injection ninject inversion-of-control

现在我有一些服务在一个不依赖于IoC容器的程序集中定义(在我的例子中为Ninject).在主项目中,我有一个用于在容器中注册的数据访问的IRepository.

this.Bind<IRepository>().To<EntityFrameworkRepository<MyDatabaseEntities>>();
Run Code Online (Sandbox Code Playgroud)

我还注册了IAuthenticationService和IErrorLogger服务,其具体实现我想将存储库用于其逻辑.但是,我不确定如何最好地完成这一任务.目前,我在两个具体实现上的构造函数都接受一个I​​Repository参数,并在我注册它时将其传递给它:

this.Bind<IAuthenticationService>().To<MyAuthenticationService>().
                WithConstructorArgument("myRepository", ctx => ctx.Kernel.Get<IRepository());
Run Code Online (Sandbox Code Playgroud)

在这里,我只是告诉容器抓取IRepository实例并将其传递给构造函数.

我觉得让我的服务组件依赖于ninject甚至是公共服务定位器(CSL)是不对的,但我也不确定我当前的方式.我正在寻找意见和替代解决方案.

如果我的其他服务不使用IRepository,我将不得不为每种类型的底层IRepository类型创建这些服务的新具体实现(例如,伪造和真实数据的AuthenticationService).这将是很多逻辑重复.

Bro*_*ass 6

您的服务程序集不应该依赖于Ninject,只能依赖于您注册具体类型的接口.IoC容器应该只是聚合根,以便将依赖项注入到类中.另一方面,包含聚合根/ Ninject内核的程序集将依赖于包含具体类型的所有程序集(它还能如何解析它们?).

在一般国际奥委会应该应用好莱坞原则在这里-你应该依赖于你的具体对象实例(使用构造器注入,如果可能的话),而不是让对象实例要求对它们的依赖.

WithConstructorArgument()实际上根本不需要您使用的示例,因为依赖项解析以递归方式工作:您已经注册了容器,IRepository并且已经注册IAuthenticationService了容器,因此它知道如何解决这两个问题.因为IAuthenticationService绑定AuthenticationService你不需要指定构造函数参数,因为它是类型的IRepository并且将自动解析.

至于重复 - 当然,您必须为不同的存储库类型创建不同的实现,IRepository假设您需要这些存储库的不同行为.

  • 对于Ninject,你可以使用`WhenInjectedInto <Foo>()`,其中Foo是你的服务类.通常,您只会注册存储库的一个具体实现 - 假数据和测试的实现不应该作为主应用程序的一部分注册,只能在单独的测试容器中注册 (2认同)