Как предоставить IServiceProvider в качестве зависимости, когда вы делаете экземпляры в DI вручную?
контекст
У меня есть 5 услуг:
Service1 (no depends.)
Service2 (no depends.)
Service3 (Service1, Service2, IServiceProvider) : ISpecialService
Service4 (Service1, Service2, Service3) : ISpecialService
Service5 (Service1, Service3, Service4) : ISpecialService
Все они представляют собой синглтон-сервисы по одному экземпляру на каждое приложение. Обычно вы просто добавляете их как синглтоны и 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, я не могу найти способ предоставить полный экземпляр ISP экземпляру Service3. Если я создаю провайдера, я больше не могу добавлять какие-либо сервисы, что является тупиком, потому что 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>()
}
Причина, по которой мне нужно зарегистрировать Сервис 3,4,5 в качестве типа интерфейса, заключается в некоторой обычной работе с контактами, которую я хочу сделать позже:
foreach (var srv in ISP.GetService<ISpecialService>())
{
serv.Startup();
}
Есть идеи как решить это?
1 ответ
Что вы можете сделать, это:
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();
}
}