Let's say I have an interface IDependencyResolver:
public interface IDependencyResolver{
T Resolve<T>() where T: class;
object Resolve(Type source);
}
And an implementation with the use of SimpleInjector:
public class SIDependencyResolver:IDependencyResolver{
private readonly Container _container;
public SIDependencyResolver(Container container){
_container = container;
_container.Options.DefaultScopedLifestyle = new WcfOperationLifeStyle();
RegisterDependencies(_container, LifeStyle.Scoped);
}
public T Resolve<T>() where T:class{
return _container.GetInstance<T>();
}
public object Resolve(Type source){
return _container.GetInstance(source);
}
public void RegisterDependencies(Container container, LifeStyle lifeStyle){
//register dependencies + register self
}
}
What do I need to do if I need the IDependencyResolver injected in a constructor which uses the Service locator pattern? (yes, I know... an anti-pattern... but this aside)
public class UnitOfWork: IUnitOfWork{
private readonly IDependencyResolver _resolver;
public UnitOfWork(IDependencyResolver resolver){
_resolver = resolver;
}
public IReadRepository<T> Read<T>(){
return _resolver.Resolve<IReadRepository<T>>();
}
public IWriteRepository<T> Write<T>(){
return _resolve.Resolve<IWriteRepository<T>>();
}
}
In the past I always registered the dependency resolver self as a singleton, so not with a scoped lifestyle since that gave me problems.
container.Register<IDependencyResolver, SIDependencyResolver>(LifeStyle.Singleton);
First of all, is this the correct way (for example in case of WCF scope, with a singleton lifestyle) to do this or is there another way to do this?
Second, is it correct to pass the SimpleInjector.Container to the constructor of my dependencyResolver?
What do I need to do if I need the IDependencyResolver injected in a constructor which uses the Service locator pattern? (yes, I know... an anti-pattern... but this aside)
This should not be set aside. Although your approach of making the callback to the container like you're doing in your UnitOfWork
is fine, the (ab)use of such IDependencyResolver
abstraction can quickly spread out through the code base to places where it is absolutely not fine.
The usage of this IDependencyResolver
abstraction should be limited to the composition root. But since the composition root already knows about the existence of the exact DI library you are using, having this IDependencyResolver
abstraction has no benefit over depending directly on the Container
itself.
So your IUnitOfWork
implementation should be defined inside your Compostion Root and should look as follows:
private sealed class SimpleInjectorUnitOfWork : IUnitOfWork {
private readonly Container _container;
public UnitOfWork(Container container){
_container = container;
}
public IReadRepository<T> Read<T>() => _container.GetInstance<IReadRepository<T>>();
public IWriteRepository<T> Write<T>() => _container.GetInstance<IWriteRepository<T>>();
}
Registration can be done as follows:
container.RegisterSingleton<IUnitOfWork>(new SimpleInjectorUnitOfWork(container));
In the past I always registered the dependency resolver self as a singleton, so not with a scoped lifestyle since that gave me problems.
It is unclear to me what problems you had, but one thing that will cause trouble is setting the DefaultScopedLifestyle
inside a constructor, while the type is auto-wired by the container. It is much better to move this call out of such constructor; it makes it much clearer:
var container = new Container();
container.Options.DefaultScopedLifestyle = new WcfOperationLifeStyle();