2

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

  1. First off, does this seem like the right architecture to solve this particular problem of customer specific code?
  2. Is there a way to solve this using dependency injection? (we don't want a giant switch statement that just chooses which service to use based on the customer name in each action)

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.

Chris
  • 455
  • 1
  • 4
  • 13
  • Have a look at [this question](http://stackoverflow.com/questions/34649735/dynamic-selection-of-interface-implementation-using-ioc). – NightOwl888 Jan 13 '16 at 06:02
  • @NightOwl888 I like that answer, which I think goes along with Kenneth's answer with using a factory injected in instead of the service. Thanks! – Chris Jan 13 '16 at 18:38

2 Answers2

0

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.

Kenneth
  • 28,294
  • 6
  • 61
  • 84
  • I was trying to avoid using a switch statement, but at least this centralizes it in one place instead of being in every action. Thanks! – Chris Jan 13 '16 at 18:30
0

I would suggest to keep customer specific implementations in different projects. For example you can have a project named CoreServices with base functionality:

namespace CoreServices.Services
{
    public interface IServiceA
    {
        string Test { get; }
    } 

    public interface IServiceB
    {
        string Test { get; }
    }

    public class ServiceA : IServiceA
    {
        public virtual string Test 
        {
            get { return "CoreServices: ServiceA"; } 
        }
    }

    public class ServiceB : IServiceB
    {
        public virtual string Test
        {
            get { return "CoreServices: ServiceB"; }
        }
    }
}

And another project name CostomerAServices where only ServiceA is customized:

namespace CustomerAServices.Services
{
    public class ServiceA : CoreServices.Services.ServiceA
    {
        public override string Test
        {
            get { return "CustomerAServices: ServiceA"; }
        }
    }
}

Then, by running this code you will get what you need:

string customizedAssemblyName = "CustomerAServices"; // Get from config
container.Register(Classes
    .FromAssemblyNamed(customizedAssemblyName)
    .InNamespace(customizedAssemblyName + ".Services")
    .WithServiceAllInterfaces());

container.Register(Classes
   .FromAssemblyNamed("CoreServices")
   .InNamespace("CoreServices.Services")
   .WithServiceAllInterfaces());

First you will register customized versions and the base ones. So if you run this code:

var serviceA = container.Resolve<IServiceA>();
System.Console.WriteLine(serviceA.Test);

var serviceB = container.Resolve<IServiceB>();
System.Console.WriteLine(serviceB.Test);

The output will be:

CustomerAServices: ServiceA
CoreServices: ServiceB

You can read more about custom Windsor registration here and here.

Aleksandr Ivanov
  • 2,778
  • 5
  • 27
  • 35
  • This is a good way to separate out the different implementations of the services (and I'll probably use it), however, I was looking for more of an answer like Kenneth's. – Chris Jan 13 '16 at 18:28
  • It really depends on the size of your application. If it's large, then Kenneth's approach can become really messy. Resolving dependencies based on conventions also forces you to have good code structure. – Aleksandr Ivanov Jan 13 '16 at 20:41