Как получить ссылку на IHostedService с помощью внедрения зависимостей в ASP.NET Core? - PullRequest
0 голосов
/ 27 августа 2018

Подробнее

Я попытался создать структуру фоновой обработки, используя рекомендованный интерфейс IHostedService в ASP.NET 2.1. Я регистрирую услуги следующим образом:

services.AddSingleton<AbstractProcessQueue<AbstractImportProcess>>();
services.AddHostedService<AbstractBackgroundProcessService<AbstractImportProcess>>();

services.AddSignalR();

AbstractProcessQueue - это просто оболочка вокруг BlockingCollection процессов, которые можно ставить в очередь и снимать с очереди. AbstractBackgroundProcessService реализует интерфейс IHostedService и ищет в очереди новые процессы, которые он может запустить.

Теперь проблема начинается, когда внутри хаба SignalR я пытаюсь получить ссылку на службу фоновой обработки через механизмы Dependency Injection. Я пробовал следующие решения, но ни одно из них не работает должным образом:

Вариант 1:

public HubImportClient(IServiceProvider provider)
{
    //This returns null.
    var service = provider.GetService<AbstractBackgroundProcessService<AbstractImportProcess>>();
}

Вариант 2:

public HubImportClient(IServiceProvider provider)
{
    //This returns null.
    var service = (AbstractBackgroundProcessService<AbstractImportProcess>) provider.GetService(typeof(AbstractBackgroundProcessService<AbstractImportProcess>>));
}

Вариант 3:

public HubImportClient(IServiceProvider provider)
{
    //This throws an exception, because the service is missing.
    var service = provider.GetRequiredService<AbstractBackgroundProcessService<AbstractImportProcess>>();
}

Вариант 4:

public HubImportClient(IServiceProvider provider)
{
    //This throws an exception, because the service is missing.
    var service = (AbstractBackgroundProcessService<AbstractImportProcess>) provider.GetRequiredService(typeof(AbstractBackgroundProcessService<AbstractImportProcess>);
}

Вариант 5:

public HubImportClient(IServiceProvider provider)
{
    //This returns a correct service, but prevents me from adding additional AbstractBackgroundProcessService implementations with different type parameters.
    //Additionally, it seems like this reference was newly created, and not the instance that was created on application startup (i.e. the hash codes are different, and the constructor is called an additional time).
    var service = provider.GetService<IHostedService>();
    if(service is AbstractBackgroundProcessService<AbstractProcessService>)
    {    this.Service = (AbstractBackgroundProcessService<AbstractProcessService>) service;}
}

Вариант 6:

public HubImportClient(IServiceProvider provider)
{
    //This works similarly to the previous option, and allows multiple implementations, but the constructor is still called twice and the instances thus differ.
    AbstractBackgroundProcessService<AbstractImportProcess> service = null;
    foreach(IHostedService service in provider.GetServices<IHostedService>())
    {
        if(service is AbstractBackgroundProcessService<AbstractImportProcess>)
        {
            service = (AbstractBackgroundProcessService<AbstractImportProcess>) service;
            break;
        }
    }  
}

Вариант 7:

public HubImportClient(IServiceProvider provider)
{
    //This just skips the for each loop all together, because no such services could be found.
    AbstractBackgroundProcessService<AbstractImportProcess> service = null;
    foreach(AbstractBackgroundProcessService<AbstractImportProcess> current in provider.GetServices<AbstractBackgroundProcessService<AbstractImportProcess> >())
    {
        service = current;
        break;
    }    
}

Вариант 8:

//This works, but prevents multiple implementations again.
public HubImportClient(IHostedService service)
{
    this.Service = service;   
}

Вариант 9:

//This does not work again.
public HubImportClient(AbstractBackgroundProcessService<AbstractImportProcess> service)
{
    this.Service = service;   
}

Вопрос

Итак, у меня остается вопрос: как мне получить ссылку на реализацию IHostedService, чтобы:

(a): я могу ввести несколько экземпляров службы, которые отличаются только параметром типа (например, размещенная служба для AbstractImportProcess es и одна для AbstractExportProcess es)

(b): существует только один экземпляр IHostedService для этого конкретного параметра типа.

Заранее спасибо за любую помощь!

1 Ответ

0 голосов
/ 27 августа 2018

Было несколько дискуссий по этой теме.Например, см .: https://github.com/aspnet/Hosting/issues/1489. Одна из проблем, с которыми вы столкнетесь, заключается в том, что размещенные службы добавляются как временные службы (из ASP.NET Core 2.1+), что означает, что разрешение размещенной службы разрешается путем внедрения зависимостиКонтейнер будет каждый раз создавать новый экземпляр.

Общий совет - инкапсулировать любую бизнес-логику, которой вы хотите поделиться или взаимодействовать с другими сервисами, в конкретный сервис.Глядя на ваш код, я предлагаю вам реализовать бизнес-логику в классе AbstractProcessQueue<AbstractImportProcess> и сделать выполнение бизнес-логики единственной задачей AbstractBackgroundProcessService<T>.

...