在DI中手动执行实例时,如何提供IServiceProvider作为依赖项?

时间:2018-08-17 11:01:59

标签: c# dependency-injection service-provider

上下文

我有5个服务:

Service1 (no depends.)
Service2 (no depends.)
Service3 (Service1, Service2, IServiceProvider) : ISpecialService
Service4 (Service1, Service2, Service3) : ISpecialService
Service5 (Service1, Service3, Service4) : ISpecialService

它们都是每应用生命中一个实例的Singleton服务。通常,您只需将它们添加为单例和BuildServiceProvider。但是,在我的情况下,所有ISpecialService都需要两次注册:作为工厂和自己的直接类型,因此通过ctor直接注入:

public SomeOtherService(Service3 s3, Service4 s4) { }

仍然有效。 问题是,如果我只是正常注册它们:

.AddSingleton<ISpecialService, Service3>()
.AddSingleton<Service3, Service3>()

这将给我2个不同的Service3实例,这些实例将使单例失败。要拥有一个实例,在注册Service3并将实例作为参数提供给AddSingleton方法之前,我需要手动创建实例。

 var s3 = new Service3(s1, s2, ?isp?);
.AddSingleton<ISpecialService, Service3>(s3) // same instance for contract work
.AddSingleton<Service3, Service3>(s3) // same instance
...
.BuildProvider()

这是一个问题,因为Service3具有IServiceProvider作为依赖项。通常,它是由DI处理的,但是在这种情况下,我需要注册它的 SINGLE 实例两次,我似乎找不到找到向Service3提供完整ISP实例的方法。实例。如果我构建ISP,我将无法再添加任何服务,这是一个死胡同,因为Servcie3稍后将需要作为循环依赖项的变通方法,而中间没有99个中间的空无意义的服务:

private readonly Service1 service1;
private readonly Service2 service2;
private Service4 service4;
private readonly IServiceProvider ISP;

public Service3 (Service1 s1, Service2 s2, IServiceProvider isp)
{
    //assign depenencies
}

public Startup()
{
   //workaround for circular dependency
   service4 = ISP.GetServic<Service4>()
}

我需要将Service 3,4,5注册为接口类型的原因是我希望他们以后做的一些常见的联系工作:

foreach (var srv in  ISP.GetService<ISpecialService>())
{
    serv.Startup();
}

有什么想法可以解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

您可以执行以下操作:

public class Answer
{
    public Answer()
    {
        // Have your service collection, register everything you need
        // before having to add your custom service.
        var collection = new ServiceCollection()
            .AddSingleton<ISpecialService, Service3>();
            //---

        // Build a disposable container without your custom service
        var provider = collection.BuildServiceProvider();

        // Use that container to call your instance of your custom service
        var serviceInstanceWithDI = provider.GetService<ISpecialService>();
        // This way the service is pulled from the DI container with all of its 
        // dependencies injected, assuming they are registered beforehand

        // Add it back to the collection with its dependencies already injected
        collection.AddSingleton<Service3, Service3>(serviceInstanceWithDI);

        // Now you can build the IServiceProvider and have your 2 instances registered.
        var serviceProvider = collection.BuildServiceProvider();
    }
}