如何编写IOC和ServiceLocator不可知的C#类库?

时间:2016-08-19 21:47:56

标签: c# inversion-of-control unity-container ioc-container

我的应用程序处理多个客户端,每个客户端都有不同的设置。 所以我决定使用IOC容器使用key注册每个客户端特定的设置。然后我根据key找到ClientSettings。 key值将在运行时期间可用。

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;
    }
}

在MyCompany.BO名称空间中使用

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);
    }
}

主要应用程序注册客户端设置

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);

问题
RuleEngine类正在使用Microsoft.Practices.ServiceLocation.ServiceLocator根据ClientSettings找到key。这意味着实现规则引擎的C#库需要使用应用程序正在使用的相同IOC。 (在这种情况下是Unity) 如何让图书馆不知道IOC容器?
如果在运行时期间已知key值,如何在不使用ServiceLocator的情况下在此处注入客户端设置? 工厂模式是实现这一目标的唯一途径吗? (例如,我找到服务的方式_factory.GetService(clientname)

1 个答案:

答案 0 :(得分:4)

这三行:

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

看起来像纯管道,很少或没有分支。将该部分移至Composition Root。既然您已put this in your Composition Root,那么您可以使用no reason to attempt to abstract away any DI Container。相反,您可以使用DI Container的API简单地编写所需的服务,而可重用的类库将不需要知道发生的情况。