如何在ASP.NET Core中通过依赖注入获取对IHostedService的引用? [英] How do I get a reference to an IHostedService via Dependency Injection in ASP.NET Core?

查看:514
本文介绍了如何在ASP.NET Core中通过依赖注入获取对IHostedService的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

详细信息

我试图使用ASP.NET 2.1中推荐的IHostedService接口创建后台处理结构.我注册了以下服务:

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的一个实例.

在此先感谢您的帮助!

解决方案

围绕该主题进行了一些讨论.例如,请参阅: https://github.com/aspnet/Hosting/issues/1489.您将遇到的问题之一是将托管服务添加为临时服务(来自ASP.NET Core 2.1+),这意味着从依赖项注入容器中解析托管服务每次都会导致一个新实例./p>

一般建议是将要与其他服务共享或从其他服务交互的任何业务逻辑封装到特定服务中.查看代码,建议您在AbstractProcessQueue<AbstractImportProcess>类中实现业务逻辑,并使执行业务逻辑成为AbstractBackgroundProcessService<T>的唯一关注点.

Details

I have attempted to create a background processing structure using the recommended IHostedService interface in ASP.NET 2.1. I register the services as follows:

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

services.AddSignalR();

The AbstractProcessQueue is just a wrapper around a BlockingCollection of processes that can be enqueued and dequeued. The AbstractBackgroundProcessService implements the IHostedService interface and looks at the queue for new processes it can start.

Now, the trouble starts when, inside a SignalR hub, I attempt to get a reference to the background processing service via the Dependency Injection mechanisms. I have tried the following solutions, but none seem to be working as intended:

Option 1:

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

Option 2:

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

Option 3:

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

Option 4:

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

Option 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;}
}

Option 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;
        }
    }  
}

Option 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;
    }    
}

Option 8:

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

Option 9:

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

Question

So then my question remains: how am I supposed to get a reference to an IHostedService implementation so that:

(a): I can inject multiple instances of the service that differ only by their type parameter (e.g. a hosted service for AbstractImportProcesses as well as one for AbstractExportProcesses)

(b): there is only ever one instance of the IHostedService for that specific type parameter.

Thanks in advance for any help!

解决方案

There has been some discussion around this topic. For example, see: https://github.com/aspnet/Hosting/issues/1489. One of the problems that you'll run into is that hosted services are added as transient services (from ASP.NET Core 2.1+), meaning that resolving an hosted service from the dependency injection container will result in a new instance each time.

The general advice is to encapsulate any business logic that you want to share with or interact from other services into a specific service. Looking at your code I suggest you implement the business logic in the AbstractProcessQueue<AbstractImportProcess> class and make executing the business logic the only concern of AbstractBackgroundProcessService<T>.

这篇关于如何在ASP.NET Core中通过依赖注入获取对IHostedService的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆