简单的注入器 - 使用一个自定义参数注册服务

时间:2017-11-24 15:08:26

标签: c# dependency-injection ioc-container simple-injector

我尝试使用自定义参数" server"注册通信服务。但我希望自动解决ILogger依赖关系,而不是设置此依赖关系两次。

最好的办法是什么?

SimpleInjector注册

var diContainer = new Container();
diContainer.Register<ILogger, DefaultLogger>();
//Good
diContainer.Register<ICommunicationService>(
    () => new CommunicationService("server1"), 
    Lifestyle.Singleton);
//Bad
diContainer.Register<ICommunicationService>(
    () => new CommunicationService(new DefaultLogger(), "server1"),
    Lifestyle.Singleton);

CommunicationService Class

public class CommunicationService : ICommunicationService
{
    public CommunicationService(ILogger logger, string server)
    {
    }
}

更新2017-11-27

@Steven我想运行两个CommunicationService的不同配置实例。在我的示例server1和server2中。

var container = new Container();
container.Register<ILogger, DefaultLogger>();
container.RegisterSingleton(new CommunicationServiceConfig { Server = "server1" });
container.RegisterSingleton(new CommunicationServiceConfig { Server = "server2" });

diContainer.Register<ICommunicationService, CommunicationService>(Lifestyle.Singleton);
diContainer.Register<ICommunicationService, CommunicationService>(Lifestyle.Singleton);

2 个答案:

答案 0 :(得分:4)

原始类型的注入始终是DI容器的一个问题,因为string intbool等基本类型会导致歧义。

因此,最简单的解决方案是将此string配置值包装到其自己的配置类中,例如:

public class CommunicationServiceConfig
{
    public string Server { get; set; }
}

CommunicationService依靠CommunicationServiceConfig而不是string

public class CommunicationService : ICommunicationService
{
    public CommunicationService(ILogger logger, CommunicationServiceConfig config)
    {
    }
}

通过此更改,组合根变为:

var container = new Container();
container.Register<ILogger, DefaultLogger>();
container.RegisterSingleton(new CommunicationServiceConfig { Server = "server1" });

diContainer.Register<ICommunicationService, CommunicationService>(Lifestyle.Singleton);

答案 1 :(得分:1)

不理想,但似乎你可以捕获容器本身来解决已经注册的依赖关系,在实际的自举阶段本身,然后可以传递给工厂函数注册,即:

    diContainer.Register<ICommunicationService>(
        () => new CommunicationService(
         diContainer.GetInstance<ILogger>(), "server1"), Lifestyle.Singleton);

因此允许硬编码值的混合,例如,对于Config,连接字符串等,以及其他已解析的依赖项,尽管如果构造函数签名发生更改,这将导致很多维护工作。

有一点需要注意的是,SimpleInjector在第一个分辨率完成后会冻结注册,因此,例如,以下内容是不可能的:

var sharedLogger = diContainer.GetInstance<ILogger>();

diContainer.Register<ICommunicationService>(
        () => new CommunicationService(sharedLogger, "server1"), Lifestyle.Singleton);
// Other registrations with `sharedLogger`
  

System.InvalidOperationException:第一次调用GetInstance后无法更改容器

即。你需要确保你的工厂方法保持懒惰。