Можно ли расширить IServiceProvider во время выполнения - PullRequest
3 голосов
/ 09 мая 2019

TLDR: Можно ли изменить IServiceProvider после запуска автозагрузки?

Я запускаю библиотеки dll (которые реализуют мой интерфейс) во время выполнения.Поэтому есть фоновое задание прослушивателя файлов, которое ожидает, пока плагин dll не будет удален.Теперь я хочу зарегистрировать классы этой dll в системе внедрения зависимостей.Поэтому я добавил IServiceCollection как синглтон в DI внутри ConfigureServices для использования внутри другого метода.

В связи с этим я создал тест-проект и просто попытался изменить ServiceCollection в контроллере, потому чтоэто было проще, чем убрать фоновое задание.

services.AddSingleton<IServiceCollection>(services);

Поэтому я добавил IServiceCollection в свой контроллер, чтобы проверить, могу ли я добавить класс в DI после запуска класса Startup.

[Route("api/v1/test")]
public class TestController : Microsoft.AspNetCore.Mvc.Controller
{
  private readonly IServiceCollection _services;

  public TestController(IServiceCollection services)
  {
    _services = services;

    var myInterface = HttpContext.RequestServices.GetService<IMyInterface>();
    if (myInterface == null)
    {
      //check if dll exist and load it
      //....
      var implementation = new ForeignClassFromExternalDll();
      _services.AddSingleton<IMyInterface>(implementation);
    }
  }

  [HttpGet]
  public IActionResult Test()
  {
    var myInterface = HttpContext.RequestServices.GetService<IMyInterface>();
    return Json(myInterface.DoSomething());
  }
}

public interface IMyInterface { /* ... */ }

public class ForeignClassFromExternalDll : IMyInterface { /* ... */ }

Служба была успешно добавлена ​​к IServiceCollection, но изменение не сохраняется до HttpContext.RequestServices, даже после нескольких вызовов счетчик услуг увеличивается каждый раз, но я не получаю ссылку по IServiceProvider.

Теперь мой вопрос: возможно ли это достичь и да, как?Или мне лучше этого не делать?

1 Ответ

2 голосов
/ 09 мая 2019

Можно ли изменить IServiceProvider после запуска автозагрузки?

Краткий ответ: Нет .

Как только IServiceCollection.BuildServiceProvider()Если изменения вызваны, любые изменения в коллекции не влияют на встроенный поставщик.

Используйте делегат фабрики, чтобы отложить загрузку внешней реализации, но это должно быть сделано при запуске, как и при остальной регистрации.

services.AddSingleton<IMyInterface>(_ => {
    //check if dll exist and load it
    //....
    var implementation = new ForeignClassFromExternalDll();
    return implementation;
});

Теперь вы можете явно добавить свой интерфейс в конструктор контроллера

private readonly IMyInterface myInterface;

public MyController(IMyInterface myInterface) {
    this.myInterface = myInterface;
}

[HttpGet]
public IActionResult MyAction() {
    return Json(myInterface.DoSomething());
}

, и логика загрузки DLL будет вызываться при разрешении этого интерфейса при разрешении контроллера.

...