一般的IoC实践 - 服务相互依赖是不对的?

时间:2022-03-27 13:00:00

Right now I have a few services that are defined in an assembly that is not dependent on an IoC container (Ninject in my case). In the main project I have an IRepository for data access registered in the container.

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

this.Bind<IRepository>().To<EntityFrameworkRepository<MyDatabaseEntities>>();

I also have IAuthenticationService and IErrorLogger services registered, whose concrete implementation I want to use the repository for their logic. However, I am not sure how to best accomplish this. Currently, my constructor on both concrete implementations take an IRepository parameter and I pass it in when I register them:

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

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

Here I just tell the container to grab the IRepository instance and pass it to the constructor.

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

I didn't feel right about making my service assembly depend on ninject or even the common service locator (CSL), but I am not sure about my current way either. I am looking for opinions and alternate solutions.

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

If my other services don't use an IRepository, I would have to create new concrete implementations of these services for each type of underlying IRepository type (e.g. an AuthenticationService for both fake and real data). It would be a lot of logic repetition.

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

1 个解决方案

#1


6  

Your service assembly should not depend on Ninject, only on the interfaces that you register your concrete types for. The IoC container should be only the aggregate root to inject dependencies into your classes. The assembly that contains the aggregate root / the Ninject kernel on the other hand will depend on all of the assemblies that contain the concrete types (how else would it be able to resolve them?).

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

In general with IoC you should apply the Hollywood principle here - you should give the dependencies to your concrete object instances (using constructor injection if at all possible), not let the object instances ask for their dependencies.

通常在IoC中,您应该在这里应用好莱坞原则 - 您应该将依赖项提供给具体的对象实例(如果可能的话,使用构造函数注入),不要让对象实例请求它们的依赖项。

The example you use for WithConstructorArgument() should not be needed at all actually, since dependency resolution works recursively: You have registered both IRepository and IAuthenticationService with the container, so it knows how to resolve both. Because IAuthenticationService is bound to AuthenticationServiceyou do not need to specify the constructor argument since it is of type IRepository and will be resolved automatically.

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

As to the repetition - of course you will have to create different implementations for IRepository for different repository types assuming you want different behavior of these repositories.

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

#1


6  

Your service assembly should not depend on Ninject, only on the interfaces that you register your concrete types for. The IoC container should be only the aggregate root to inject dependencies into your classes. The assembly that contains the aggregate root / the Ninject kernel on the other hand will depend on all of the assemblies that contain the concrete types (how else would it be able to resolve them?).

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

In general with IoC you should apply the Hollywood principle here - you should give the dependencies to your concrete object instances (using constructor injection if at all possible), not let the object instances ask for their dependencies.

通常在IoC中,您应该在这里应用好莱坞原则 - 您应该将依赖项提供给具体的对象实例(如果可能的话,使用构造函数注入),不要让对象实例请求它们的依赖项。

The example you use for WithConstructorArgument() should not be needed at all actually, since dependency resolution works recursively: You have registered both IRepository and IAuthenticationService with the container, so it knows how to resolve both. Because IAuthenticationService is bound to AuthenticationServiceyou do not need to specify the constructor argument since it is of type IRepository and will be resolved automatically.

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

As to the repetition - of course you will have to create different implementations for IRepository for different repository types assuming you want different behavior of these repositories.

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