We have a situation where we are using Castle Windsor dependency injection to inject an IService
into a wep api controller like so:
public FooController : ApiController
{
private IService _service;
public FooController(IService service)
{
_service = service;
}
}
And registering the service like this:
container.Register(Component.For<IService>().ImplementedBy<Service>().LifestyleTransient());
Where service is something like:
public Service : IService
{
public virtual string Logic()
{
return "Service Logic";
}
}
The problem is, some customers have semi different business logic then what the base has, so we need to use another implementation of Service
that does what that customer needs.
So if there is 2 customers (Customer1 and Customer2), Customer1 should use the default Service
, but Customer2 should use a custom implementation called Customer2Service
which will inherit from Service
and override as needed like so:
public Customer2Service : Service
{
public override string Logic()
{
var response = base.Logic();
return "Customer 2 Logic " + response;
}
}
Questions
What we've tried
We tried to change the dependency injection to be property based like so:
public FooController : ApiController
{
private IService _service;
public FooController()
{
}
public HttpResponseMessage FooAction(string customer)
{
_service = container.Resolve<IService>(customer);
...
}
}
container.Register(Component.For<IService>().ImplementedBy<Service>().LifestyleTransient());
container.Register(Component.For<IService>().ImplementedBy<Customer2Service>().LifestyleTransient().Named("Customer2"));
The problem with this is, we have to have a custom service for each customer even if they didn't need it which can get unwieldy. Otherwise the resolve would throw an exception saying that named dependency doesn't exist.
You can use a factory here:
class ServiceFactory : IServiceFactory
{
public IService GetService(string customer)
{
switch (customer)
{
case "special":
return container.Resolve<IService>("special");
default:
return container.Resolve<IService>("default");
}
}
}
Then you can inject the factory into your controllers and get an IService
from the factory.
In the switch statement you only declare the special cases, all the other ones fo to the default clause.