LP13
LP13

Reputation: 34109

How to write IOC and ServiceLocator agnostics C# class library?

My application deals with multiple clients and each client has different settings. So I have decided to use IOC container to register each client specific settings using a key. Then i am locating ClientSettings based on akey. key value will be available during runtime.

C# Library MyCompany.BO

public class ClientSettings : IClientSettings
{

    public string ClientApiKey { get; private set}
    public string ClientId { get; private set}

    public static IClientSettings Load(string clientname)
    {
        // Load the client specific information from JSON file using clientname
        var cs = new ClientSettings();
        cs.ClientApiKey = "Some client specific key";
        cs.ClientId = "Some client specific key";
        return cs;
    }
}

Consumed in MyCompany.BO namespace

public class RuleEngine : IRuleEngine
{
    IFactory _factory;
    RuleEngine(IFactory factory)
    {
        factory = _factory;
    }

    public void Run(string request)
    {
        var clientname = ParseStringToGetClientName(request)


           var clientSettings = ServiceLocator.Current.GetInstance<IClientSettings>(clientname);

        var service = _factory.GetService(clientname);

        service.DoWork(clientSettings);
    }
}

Main Application registering the client settings

var container = new UnityContainer();

var clientASettings = ClientSettings.Load("ClientA");
var clientBASettings = ClientSettings.Load("ClientB");
var clientCSettings = ClientSettings.Load("ClientC");

// register singleton instance
container.RegisterInstance("ClientA", clientASettings);
container.RegisterInstance("ClientB", clientBSettings);
container.RegisterInstance("ClientC", clientCSettings);

Question
The RuleEngine class is using Microsoft.Practices.ServiceLocation.ServiceLocator to locate ClientSettings based on the key. That means C# library where rule engine is implemented needs to use the same IOC that application is using. (Which is Unity in this case)
How do I make library unaware of IOC container?
How do I inject clientsettings here without using ServiceLocator when the key value known during runtime? Is the factory pattern the only way to achieve this? (For example the way I am locating service _factory.GetService(clientname))

Upvotes: 0

Views: 904

Answers (1)

Mark Seemann
Mark Seemann

Reputation: 233150

These three lines:

var clientname = ParseStringToGetClientName(request);    
var clientSettings = ServiceLocator.Current.GetInstance<IClientSettings>(clientname);        
var service = _factory.GetService(clientname);

look like pure plumbing with little or no branching. Move that part to your Composition Root. Since you've put this in your Composition Root, there's no reason to attempt to abstract away any DI Container you may use. Instead, you can simply compose the desired services using the API of the DI Container, and the reusable class library will not need to know how that happened.

Upvotes: 4

Related Questions