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.
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 AuthenticationService
you 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With