I have the following installer but for some odd reason it is not resolving correctly. I have an interface where there are 2 implementations of it but want to inject the correct instance based on naming conventions
.
I am expecting in this instance that the correct instance of ICommand
will be injected based on how they are named. However, for some odd reason both controllers are picking the very first instance, i.e. FooCommand
due to it being defined first in the installer.
Not sure what I have done wrong? Perhaps, is there an alternative way of doing this?
public interface ICommand { }
public class FooCommand : ICommand { }
public class BarCommand : ICommand { }
public class SomeController : ApiController
{
public SomeController(ICommand fooCommand) { }
}
public class HelloController : ApiController
{
public HelloController(ICommand barCommand) { }
}
container.Register(
Component.For<ICommand>()
.Named("fooCommand")
.ImplementedBy<FooCommand>()
.LifestyleSingleton(),
Component.For<ICommand>()
.Named("barCommand")
.ImplementedBy<BarCommand>()
.LifestyleSingleton());
Like @steven said, it's generally not a good idea and if not managed properly may lead to discoverability issues down the line, but assuming you know what you're doing you can build a IContributeComponentModelConstruction
that will match constructor parameters of type ICommand
on your controllers with Windsor components having the same name.
public class ControllerCommandMatcher : IContributeComponentModelConstruction
{
public void ProcessModel(IKernel kernel, ComponentModel model)
{
// or whatever other condition to bail out quickly
if (model.Implementation.Name.EndsWith("Controller") == false) return;
foreach (var constructor in model.Constructors)
{
foreach (var dependency in constructor.Dependencies)
{
if (dependency.TargetItemType != typeof (ICommand)) continue;
dependency.Parameter = new ParameterModel(dependency.DependencyKey,
ReferenceExpressionUtil.BuildReference(dependency.DependencyKey));
}
}
}
}
The tricky bit is this:
new ParameterModel(dependency.DependencyKey,
ReferenceExpressionUtil.BuildReference(dependency.DependencyKey))
It basically tells Windsor that the dependency (the constructor parameter), for example fooCommand
should be satisfied with a component of the same name (fooCommand
).
Then add your contributor to the container
container.Kernel.ComponentModelBuilder.AddContributor(new ControllerCommandMatcher());