Regarding the docs of SimpleInjector on using the decorator pattern with decoratee factories, I've run into the following problem.
Suppose I have a similar ThreadScopedCommandHandlerProxy<T>
with the following implementation:
public class LifetimeScopeCommandHandlerProxy<T> : ICommandHandler<T>
{
private readonly IScopeStarter _scopeStarter;
private readonly IServiceFactory<ICommandHandler<T>> _decorateeFactory;
public LifetimeScopeCommandHandlerProxy(
IScopeStarter scopeStarter,
IServiceFactory<ICommandHandler<T>> decorateeFactory)
{
_scopeStarter = scopeStarter;
_decorateeFactory = decorateeFactory;
}
[DebuggerStepThrough]
public void Handle(T command)
{
using (_scopeStarter.BeginScope())
{
ICommandHandler<T> handler = _decorateeFactory.CreateInstance();
handler.Handle(command);
}
}
}
Normally I would've injected a Func<ICommandHandler<T>>
into the proxy, but I wanted to abstract away from this and created a IServiceFactory which internally just does this:
public class SimpleInjectorServiceFactory<TService> : IServiceFactory<TService>
{
private readonly Func<TService> _factory;
public SimpleInjectorServiceFactory(Func<TService> factory)
{
_factory = factory;
}
public TService CreateInstance()
{
return _factory.Invoke();
}
}
You can see the reasoning behind this by looking at the class name, this is a Simple Injector specific factory. Now I know that using a factory abstraction like this would introduce a code smell. But in this case it should only be used as an infrastructural component. The idea is that I want the Proxy to be something that can be consumed by multiple libraries/applications, so making it a generic component within the application's architecture.
Now the problem is of course, that I get the following exception:
For the container to be able to use LifetimeScopeCommandHandlerProxy<TCommand>
as a decorator, its constructor must include a single parameter
of type ICommandHandler<TCommand> (or Func<ICommandHandler<TCommand>>)
- i.e. the type of the instance that is being decorated.
The parameter type ICommandHandler<TCommand> does not currently exist
in the constructor of class LifetimeScopeCommandHandlerProxy<TCommand>.'
Now this exception message is crystal clear, and I understand the reasoning behind this. But still, I'd like to know if it's possible to bypass the exception?
I'd like to know if it's possible to bypass the exception
There is no way to do this, without completely bypassing and reimplementing Simple Injector's decorator sub system.
Simple Injector's sub system intercepts the building of a service by wrapping a decorator. Although the decorator sub system will outsource the creation of the decorator and its dependencies back to Simple Injector's core infrastructure, it will override the creation of the dependency that capture the decorated instance. This behavior is hard-coded in the decorator sub system, which means it is impossible to move the type's decoratee to a sub class of the decorator.