'How to use dependency injection with inheritance in C#
Introduction
Hi everyone, I'm currently working on a persistence library in C#. In that library, I have implemented the repository pattern where I'm facing a SOLID issue. Here is a simplified example my current implementation to focus on the essential:
The abstract repository containing in the persistence library:
public abstract class Repository<T>
{
protected Repository(
IServiceA serviceA,
IServiceB serviceB)
{
/* ... */
}
}
The concrete repository created by the library user:
public class FooRepository : Repository<Foo>
{
protected FooRepository(
IServiceA serviceA,
IServiceB serviceB) :
base(serviceA, serviceB)
{
/* ... */
}
}
Problem
OK, with the current code, the derived class has to know every dependency of the base class which can be ok, but what if I add a dependency to the base class? Every derived class will break because they will need to pass that new dependency to the base class... So currently, I'm limited to never change the base class constructor and it's a problem because I want my base class to had the possibility to evolve. This implementation clearly breaks the Open/Closed Principle, but I don't know how to solve this issue without breaking the SOLID...
Requirements
- The library should be easy to use for the user
- The concrete repositories should be able to be constructed through the DI
- One or more dependencies should be added to the abstract repository without impacting the derived repositories
- It should be possible to register every repository in the DI container using a naming convention as does the ASP.NET MVC framework with the controllers
- The user should be able to add more dependencies in his derived repository if he wants
Solutions already envisaged
1. Service aggregator pattern
Following this article, the service aggregator model can be applied in this situation so the code would look like something like this:
The abstract repository containing in the persistence library:
public abstract class Repository<T>
{
public interface IRepositoryDependencies
{
IServiceA { get; }
IServiceB { get; }
}
protected Repository(IRepositoryDependencies dependencies)
{
/* ... */
}
}
The concrete repository created by the library user:
public class FooRepository : Repository<Foo>
{
protected Repository(IRepositoryDependencies dependencies) :
base(dependencies)
{
/* ... */
}
}
Pros
- The derived classes don't break if a dependency is added to the base class
Cons
- The implementation of the
IRepositoryDependenciesinterface has to be modified if we add a dependency - The article doesn't explain how to use Castle DynamicProxy2 (which is an unknown technology for me) to dynamically generate the service aggregator
2. Builder pattern
Perhaps, it's possible to remove the base repository constructor and introduce a builder template to create the repositories, but for this solution to work, the builder must be inheritable to allow the user to enter his repository own dependencies.
Pros
- The derived classes don't break if a dependency is added to the base class
- The repositories construction is managed by another class
Cons
- The user has to create a builder for each repository he wants to create
- It's become harder to register every repository through the DI using a naming convention
3. Property injection
Perhaps removing the base repository constructor and configuring the DI to use property injection might be an option.
Pros
- The derived classes don't break if a dependency is added to the base class
Cons
- I think the property setter must be public?
Conclusion
Is there any of the mentioned solutions that could be acceptable in a SOLID world? If not, do you have a solution for me guys? You help is very appreciated!
Solution 1:[1]
After some years of experience, I found the Decorator Pattern a perfect fit for this.
Implementation:
// Abstract type
public interface IRepository<T>
{
Add(T obj);
}
// Concete type
public class UserRepository : IRepository<User>
{
public UserRepository(/* Specific dependencies */) {}
Add(User obj) { /* [...] */ }
}
// Decorator
public class LoggingRepository<T> : IRepository<T>
{
private readonly IRepository<T> _inner;
public LoggingRepository<T>(IRepository<T> inner) => _inner = inner;
Add(T obj)
{
Console.Log($"Adding {obj}...");
_inner.Add(obj);
Console.Log($"{obj} addded.");
}
}
Usage:
// Done using the DI.
IRepository<User> repository =
// Add as many decorators as you want.
new LoggingRepository<User>(
new UserRepository(/* [...] */));
// And here is your add method wrapped with some logging :)
repository.Add(new User());
This pattern is awesome, because you can encapsulate behaviors in separate classes without breaking changes and using them only when you really need them.
Solution 2:[2]
As asked by you, here is one very basic and crude sample of solving this problem through Composition rather than inheritance.
public class RepositoryService : IRepositoryService
{
public RepositoryService (IServiceA serviceA, IServiceB serviceB)
{
/* ... */
}
public void SomeMethod()
{
}
}
public abstract class Repository
{
protected IRepositoryService repositoryService;
public (IRepositoryService repositoryService)
{
this.repositoryService= repositoryService;
}
public virtual void SomeMethod()
{
this.repositoryService.SomeMethod()
.
.
}
}
public class ChildRepository1 : Repository
{
public (IRepositoryService repositoryService) : base (repositoryService)
{
}
public override void SomeMethod()
{
.
.
}
}
public class ChildRepository2 : Repository
{
public (IRepositoryService repositoryService, ISomeOtherService someotherService) : base (repositoryService)
{
.
.
}
public override void SomeMethod()
{
.
.
}
}
Now, the abstract base class and each child repository class here will only depend on IRepositoryService or any other required dependency (refer ISomeOtherService in ChildRepository2).
This way your child repository only supplies IRepositoryService dependency to your base class and you do not need to supply the dependencies of IRepositoryService anywhere.
Solution 3:[3]
It might be a bit late, but you can use the IServiceProvider in the constructor instead:
The abstract repository containing in the persistence library:
public abstract class Repository<T>
{
protected Repository(IServiceProvider serviceProvider)
{
serviceA = serviceProvider.GetRequiredService<IServiceA>();
serviceB = serviceProvider.GetRequiredService<IServiceB>();
/* ... */
}
}
The concrete repository created by the library user:
public class FooRepository : Repository<Foo>
{
protected FooRepository(IServiceProvider serviceProvider)
:base(serviceProvider)
{
serviceC = serviceProvider.GetRequiredService<IServiceC>();
serviceD = serviceProvider.GetRequiredService<IServiceD>();
/* ... */
}
}
This way each of the classes can utilize their own services without any cross-dependency.
There are downsides to this approach. First, this is a sort of service locator (anti)pattern with an abstract locator, though that does not mean it's not supposed to be used anywhere. Just be judicial about it, and make sure there isn't a better solution. Second, there is no compile-time enforcement to supply the necessary service implementations to any of the repository classes. Meaning, this will still compile if you do not put concrete implementation of IServiceA into the service provider. And then, it will fail run-time. However, in this case, that was one of your requirements.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | lopezbertoni |
| Solution 2 | Ankit Vijay |
| Solution 3 | Sanabalis Dragon |
