Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

General IoC practice - is it wrong for services to depend on each other?

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.

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:

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.

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.

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.

like image 421
Adam Avatar asked Feb 13 '12 18:02

Adam


1 Answers

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?).

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.

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.

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.

like image 132
BrokenGlass Avatar answered Oct 07 '22 07:10

BrokenGlass