I'm relatively new to dependency injection. I think I get the idea, but I'm now presented with this problem. Assume that I have some interfaces and some classes:
interface IA<T>
interface IB<IA<T>>
class A<T> : IA<T>
class B<IA<T>> : IB<IA<T>>
I want to register the following in my dependency injection container:
container.Register<IB<IA<T>>, B<A<T>>(...);
When I try to resolve IB<IA<T>>, it fails with an exception explaining that IB<IA<T>> cannot be converted to B<A<T>>.
Why did it fail, and how can I fix it?
Like Alexei posted already you wouldn't use generics that way. You would probably want something like this instead:
public interface IA<T>
{
T Item { get; }
}
public interface IB<T>
{
IA<T> IA { get; }
}
Sample implementations:
public class A<T> : IA<T>
{
public T Item
{
get;
set;
}
}
public class B<T> : IB<T>
{
public B(IA<T> ia)
{
this.IA = ia;
}
public IA<T> IA
{
get;
private set;
}
}
Since the subject is dependency injection notice the B implementation does not have parameterless constructor. Instead it notifies its dependency in the constructor.
Setting up the container, first register IA implementation:
container.Register<IA<int>, A<int>>(); // specific implementation or
container.Register(typeof(IA<>), typeof(A<>)); // generic registration
Registering IB would be the same and the container should take care of injecting the dependency to class B's constructor:
container.Register<IB<int>, B<int>>();
container.Register(typeof(IB<>), typeof(B<>));
Resolving at runtime you would need to specify the type:
var intIB = container.Resolve<IB<int>>();
var stringIB = container.Resolve<IB<string>>();
Related
I have a project using Dependency Injection (Ninject) where I have the following class:
public class SecurityService : BaseService
{
ISecurityRepository _securityRepo = null;
public SecurityService(ISecurityRepository securityRepo)
{
_securityRepo = securityRepo;
}
}
Because BaseService is going to be referenced in many other service classes I wanted to add there a method that also go to Data Repository and get some information so I don't have to repeat the same code along the other service classes.
Here is what I have for BaseRepository:
public partial class BaseService
{
IEntityRepository _entityRepo = null;
public BaseService(IEntityRepository entityRepo)
{
_entityRepo = entityRepo;
}
public Settings AppSettings
{
get
{
return _entityRepo.GetEntitySettings();
}
}
}
But when I compile I get the following error:
There is no argument given that corresponds to the required formal parameter 'entityRepo' of 'BaseService.BaseService(IEntityRepository)'
And the error make sense because now I have a constructor that I guess is expecting something.
Any clue how to fix this but that I can still have my dependency injection in BaseRepository class?
UPDATE
I just tried to remove the constructor and use the attribute [Inject] but when debugging I see that _entityRepo is NULL.
Add the dependency to the constructor for the derived class, and pass it along.
public SecurityService(ISecurityRepository securityRepo, IEntityRepository entityRepo)
: base(entityRepo)
{
_securityRepo = securityRepo;
}
I could make it work:
I just convert the private property to be public and then [Inject] attribute started to work.
public partial class BaseService
{
[Inject]
public IEntityRepository EntityRepo { get; set; }
}
Pass the Repository object to the base class via the child class constructor:
public SecurityService(ISecurityRepository securityRepo) : base(IEntityRepository)
{
//Initialize stuff for the child class
}
I'm attempting to inject a property using ninject. Given the two bindings in the ninject module below, I would expect the ConcreteDependency to be injected into B. However, it seems that WhenInjectedInto doesn't consider the type being injected into, just the declaring type of the target (property in this case).
Is there a way to achieve the behaviour I expected?
static void Main(string[] args)
{
var kernel = new StandardKernel(new TestModule());
var b = kernel.Get<B>();
var c = kernel.Get<C>();
}
class TestModule : NinjectModule
{
public override void Load()
{
Bind<IDependency>().To<EmptyDependency>();
Bind<IDependency>().To<ConcreteDependency>().WhenInjectedInto<B>();
}
}
abstract class A
{
[Inject]
public IDependency Dependency { get; set; }
}
class B : A {}
class C : A {}
interface IDependency {}
class EmptyDependency : IDependency { }
class ConcreteDependency : IDependency { }
You should use constructor injection instead of property injection if possible. This is a better technique, which is recommended by Mark Seeman, because makes dependencies required for object construction explicit and object signature via constructor is more expressive. Code should look like this:
abstract class A
{
public IDependency Dependency { get; private set; }
public A (IDependency dependency)
{
Dependency = dependency;
}
}
class B : A
{
public B (IDependency dependency)
: base(dependency)
{
}
}
class C : A
{
public C (IDependency dependency)
: base(dependency)
{
}
}
interface IDependency { }
class EmptyDependency : IDependency { }
class ConcreteDependency : IDependency { }
Configuration will be the same as in you example. The following test passes
[Test]
public void TestSpecificBindingToObjectB()
{
var kernel = new StandardKernel(new TestModule());
var b = kernel.Get<B>();
var c = kernel.Get<C>();
Assert.AreNotEqual(b.Dependency.GetType(), c.Dependency.GetType());
Assert.AreEqual(typeof(ConcreteDependency), b.Dependency.GetType());
}
If you have an optional dependency with default implementation and you are ok with decorating your classes with Inject attribute, you can can pull parent information from request, like this:
class TestModule : NinjectModule
{
public override void Load()
{
Bind<IDependency>().To<EmptyDependency>();
Bind<IDependency>().To<ConcreteDependency>().When(req =>req.ParentContext.Request.Service == typeof(B));
}
}
Then the same test given above passes for your class hierarchy with property injection.
In order to check against a concrete type, you can use ParentContext.Plan.Type on the IRequest interface. This should give you the behaviour you expected from WhenInjectedInto. For example:
When(req => req.ParentContext.Plan.Type == typeof(B))
I have a base repository contract which other contracts extend, like follows
public interface IBaseRepository<T> where T : class
{
IList<T> GetContents();
}
and then there are other contracts which extend it like follows
public interface IRepository1 : IBaseRepository<MyClass1>
{
}
public interface IRepository2 : IBaseRepository<MyClass2>
{
}
I implement IRepository1 as follows
public class Repository1 : IRepository1
{
public IList<MyClass1> GetContents()
{
//some code goes here
}
}
similarly for IRepository2
public class Repository2 : IRepository2
{
public IList<MyClass2> GetContents()
{
//some code goes here
}
}
Now i have a service Service1 which implments IService like follows
public class Service1 : IService
{
}
I want to use my base repository (IBaseRepository) here in my service constructor, get an instance of this base repository and use it like so
public class Service1 : IService
{
private IBaseRepository<T> _baseRepository;
public Service1(IBaseRepository<T> baseRepository)
{
_baseRepository = baseRepository;
}
public MyMethod1()
{
var contentsOfType1 = _baseRepository<MyClass1>.GetContents();
}
public MyMethod1()
{
var contentsOfType2 = _baseRepository<MyClass2>.GetContents();
}
}
and this is what i am unable to do.
So i have a generic base repository contract with type T and have other contracts (interfaces) extending the base contract and also specifying what type T will be.
All these contracts (which extend generic base contract) have thier individual implementations.
What i want to do is in my service class, instantiate this generic base contract, and use it to infer the extending types (and hence implementations) and use the method from the base repository.
So if the base contract is
IBaseRepository<T>
and extending contract is
IRepository1 : IBaseRepository<MyClass1>
which is implemented by
Repository1 : IRepository1
i want to use this in my service class like
public class service()
{
*private IBaseRepository<T> _repo;
public service(IBaseRepository<T> repo)
{
*_repo = repo;
}
public void MyMethod()
{
*var x = _repo<MyClass1>.MethodFromIBaseRepository()
}
}
So its the *marked lines i want to achieve, which i am unable to.
I am using castle windsor for DI.
Thanks for your help guys
You should not have other repository interfaces besides your generic IRepository<T>. If you need those, you are missing an abstraction.
For instance, a common reason for people to have custom repository interfaces is because they have a custom query that some repository has, while other don't. For instance:
public interface IEmployeeRepository : IRepository<Employee>
{
Employee GetEmployeeOfTheMonth(int month);
}
The problem here is that the IEmployeeRepository is abused for a 'custom query'. Custom queries deserve their own (generic) abstraction:
// Defines a query
public interface IQuery<TResult>
{
}
// Defines the handler that will execute queries
public interface IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
With this abstraction we can add custom queries to the system, without the need of creating IRepository<T> derivatives:
public class GetEmployeeOfTheMonthQuery : IQuery<Employee>
{
[Range(1, 12)]
public int Month { get; set; }
}
class GetEmployeeOfTheMonthHandler : IQueryHandler<GetEmployeeOfTheMonthQuery, Employee>
{
public Employee Handle(GetEmployeeOfTheMonthQuery query)
{
// todo: query the database, web service, disk, what ever.
}
}
A consumer that needs to know the employee of the month, can now simply take a dependency on IQueryHandler<GetEmployeeOfTheMonthQuery, Employee> and execute the query as follows:
var query = new GetEmployeeOfTheMonthQuery { Month = 11 };
var employee = this.employeeOfMonthHandler.Handle(query);
This might seem like overhead, but this model is very flexible, scalable, and has many interesting benefits. For instance, it is very easy to add cross-cutting concerns by wrapping handlers with decorators.
This also allows our reposities to be hidden behind one generic interface, which allows us to easily batch register them at once and add decorators to them as well.
For more in depth information, read this article: Meanwhile… on the query side of my architecture.
Not possible. The inversion of control container provide dependencies through the constructor, hence it must know in the constructor what type you want to get. So you should do this:
public class service()
{
private IBaseRepository<MyClass1> _repo;
public service(IBaseRepository<MyClass1> repo)
{
_repo = repo;
}
public void MyMethod()
{
var x = _repo.MethodFromIBaseRepository()
}
}
I have a design issue and am looking for the best design solution. I have added an example of the issue below.
public interface IVehicle<T>
{
int GetEngineSize();
}
public class Car : IVehicle<Car>
{
public int GetEngineSize()
{
throw new NotImplementedException();
}
public bool HasSpolier()
{
return true;
}
}
public class Bus : IVehicle<Bus>
{
public int GetEngineSize()
{
throw new NotImplementedException();
}
}
public abstract class BaseController<T>
{
public IVehicle<T> Repository { get; set; }
}
public abstract class CarController : BaseController<Car>
{
public CarController()
{
// How can I access the HasSpolier method from the IVehicle<T> without having to cast the Interface to concrete class Car
bool result = Repository.HasSpolier();
}
}
I'm not sure your generics are doing what you want here.
If instead of
IVehicle<T> Repository {get; set;}
You did
T Repository {get; set;}
You could make
public abstract class BaseController<T> where T : IVehicle
To ensure that they're of the IVehicle Interface
Then you'd have a typed repository and get access to your spoiler method.
You're doing IVehicle<Bus> but at least in the sample code, the T is never used in the interface. At this point the T is worthless.
Unless you implement the method in the interface, you can't access it without casting it to another class.
You'd have to cast your Repository to Car.
It would make using your interface pointless as the dependency on the implementation which you're trying to remove is re-introduced.
Also the type parameter on your interface isn't required, you don't use it anywhere else in the interface...
public interface IVehicle
{
int GetEngineSize();
}
Is it possible to inject an interface into an existing 3rd party class that I can not alter? Like extension methods but for an interface (and its implementation for the class that it had been injected to).
I like to optionally use one of two similar 3rd party libraries by giving classes that are similar in both libraries the same interfaces. So that I do not have to convert there classes into mine.
I don't completely understand what you mean about injecting an interface, but you could use the Adapter pattern to achieve this. See also: http://dofactory.com/Patterns/PatternAdapter.aspx
Create your own interface, then create your own classes that implement the interface, which contain/wrap the 3rd party classes.
As long as you're dealing with interfaces, why not just go with wrapping the classes in your own classes, that implement the interfaces?
You should look at the Decorator Pattern which allows you to extend a class by composition.
e.g.
Given sealed class A which implements InterfaceA:
public interface InterfaceA
{
int A {get; set;}
}
public sealed Class A : InterfaceA
{
public int A {get;set;}
}
You could extend InterfaceA and then use a decorator class B to encapsulate an instance of class A and provide additional methods.
public interface MyExtendedInterfaceA : InterfaceA
{
int B {get;set}
}
public class B : MyExtendedInterfaceA
{
private InterfaceA _implementsA = new A();
public int A
{
get
{
return _implementsA.A;
}
set
{
_implementsA.A = value;
}
}
public int B {get; set;}
}
Alternatively, decorator Class C could add a whole new interface:
public interface InterfaceC
{
int MethodC();
}
public class C : InterfaceA, InterfaceC
{
private InterfaceA _implementsA = new A();
public int A
{
get
{
return _implementsA.A;
}
set
{
_implementsA.A = value;
}
}
public int MethodC()
{
return A * 10;
}
}