Say I've got two classes that are instantiated by Castle Windsor, and each has a dependency on the same interface:
FooRepo
→ IApiClient
BarRepo
→ IApiClient
In this case IApiClient
is implemented by one class, GenericApiClient
, that knows how to communicate with any API. However, I want to create different instances of GenericApiClient
that are passed different config values (exposed via IApiClientConfiguration
) so that FooRepo
talks to the Foo API endpoint and the BarRepo
talks to the Bar API endpoint:
FooRepo
→ IApiClient (GenericApiClient)
→ IApiClientConfiguration (FooClientConfiguration)
BarRepo
→ IApiClient (GenericApiClient)
→ IApiClientConfiguration (BarClientConfiguration)
Here's what I've tried so far:
container = new WindsorContainer();
container.Register(
Component.For<HomeController>().LifeStyle.Transient,
Component.For<FooRepo>()
.LifeStyle.Transient,
Component.For<BarRepo>()
//.DependsOn(Dependency.OnComponent<IApiClientConfiguration, BarClientConfiguration>()) // this does nothing cause the client config is not a direct dependency :(
.LifeStyle.Transient,
Component.For<IApiClient>()
.ImplementedBy<GenericApiClient>()
//.DependsOn(Dependency.OnComponent<IApiClientConfiguration, BarClientConfiguration>()) // this overrides for both FooRepo and BarRepo :(
.LifeStyle.Transient,
Component.For<IApiClientConfiguration>()
.ImplementedBy<FooClientConfiguration>()
.LifeStyle.Transient,
Component.For<IApiClientConfiguration>()
.ImplementedBy<BarClientConfiguration>()
.LifeStyle.Transient);
I'm having trouble figuring out how to get the FooRepo
to get an instance of GenericApiClient
configured with FooClientConfiguration
, with BarRepo
getting a BarClientConfiguration
:
FooClientConfiguration
since that's what's registered firstIApiClient
using DependsOn(...)
, but that applies to both FooRepo
and BarRepo
DependsOn(...)
on the BarRepo
, it has no effect(In case the above question is not clear, I have a minimum working example here)
Is there some way I can configure Castle Windsor to do what I want? Is there some way to better structure my code so I don't have this problem?
container.Register(
Component.For<IApiClientConfiguration>()
.ImplementedBy<FooClientConfiguration>()
.Named("FooConfiguration")
.LifestyleTransient(),
Component.For<IApiClientConfiguration>()
.ImplementedBy<BarClientConfiguration>()
.Named("BarConfiguration")
.LifestyleTransient(),
Component.For<IApiClient, GenericApiClient>()
.Named("FooClient")
.DependsOn(Dependency.OnComponent(
typeof(IApiClientConfiguration), "FooConfiguration")),
Component.For<IApiClient, GenericApiClient>()
.Named("BarClient")
.DependsOn(Dependency.OnComponent(
typeof(IApiClientConfiguration), "BarConfiguration")),
Component.For<FooRepo>()
.DependsOn(Dependency.OnComponent(typeof(IApiClient), "FooClient")),
Component.For<BarRepo>()
.DependsOn(Dependency.OnComponent(typeof(IApiClient), "BarClient"))
);
It's not pretty. And there may be a way to simplify the syntax a little. Windsor usually offers a few different ways to do everything.
You're defining two different implementations of GenericApiClient
, and for each you're specifying which configuration to use. Then, when registering FooRepo
and BarRepo
, for each of them you're specifying which named implementation of IApiClient
to use.
If one or the other is the default then you can indicate it using IsDefault()
and only name the other. It can also be easier to follow if you write separate installers for separate groups of implementations, or even just methods in the same installer, like
RegisterFooDependencies(IWindsorContainer container)
{
container.Register(
Component.For<IApiClientConfiguration>()
.ImplementedBy<FooClientConfiguration>()
.Named("FooConfiguration")
.LifestyleTransient(),
Component.For<IApiClient, GenericApiClient>()
.Named("FooClient")
.DependsOn(Dependency.OnComponent(
typeof(IApiClientConfiguration), "FooConfiguration")),
Component.For<FooRepo>()
.DependsOn(Dependency.OnComponent(typeof(IApiClient), "FooClient"))
);
}