C# 如何通过ASP.NET Core中的依赖项注入获得对IHostedService的引用? 细节

C# 如何通过ASP.NET Core中的依赖项注入获得对IHostedService的引用? 细节,c#,asp.net,asp.net-core,dependency-injection,asp.net-core-2.1,C#,Asp.net,Asp.net Core,Dependency Injection,Asp.net Core 2.1,我尝试使用ASP.NET 2.1中推荐的IHostedService接口创建后台处理结构。本人注册服务如下: services.AddSingleton<AbstractProcessQueue<AbstractImportProcess>>(); services.AddHostedService<AbstractBackgroundProcessService<AbstractImportProcess>>(); services.AddSi

我尝试使用ASP.NET 2.1中推荐的
IHostedService
接口创建后台处理结构。本人注册服务如下:

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

services.AddSignalR();
备选案文2: 备选案文9:
//这又不起作用了。
public HubImportClient(AbstractBackgroundProcessService服务)
{
服务=服务;
}
问题: 因此,我的问题仍然是:我应该如何获得对
IHostedService
实现的引用,以便:

(a) :我可以插入仅因类型参数不同的多个服务实例(例如,
AbstractImportProcess
es的托管服务以及
AbstractExportProcess
es的托管服务)

(b) :对于该特定类型参数,
IHostedService
只有一个实例


提前感谢您的帮助

围绕这一话题进行了一些讨论。例如,请参阅:。您将遇到的一个问题是,托管服务被添加为临时服务(来自ASP.NET Core 2.1+),这意味着从依赖项注入容器解析托管服务每次都会产生一个新实例


一般建议是将希望与其他服务共享或从其他服务交互的任何业务逻辑封装到特定服务中。查看您的代码,我建议您在
AbstractProcessQueue
类中实现业务逻辑,并将执行业务逻辑作为
AbstractBackgroundProcessService

当前解决方案的唯一关注点:

services.AddSingleton();
services.AddSingleton(p=>p.GetService());
这会将您的服务创建为托管服务(在主机启动和关闭时运行和停止),并将其作为依赖关系注入到您需要的任何位置

更新: 我不再将此解决方案视为“变通方法”

相反,我将这样描述它:托管组件和常规服务是不同类型的实体,每个实体都有自己的用途

但是,上面的解决方案允许将它们组合起来,将托管组件注册为服务,可以在依赖项解析链中使用


这太棒了。

这只是@AgentFire对答案的一个小小修改。此方法更清晰,并且允许在单个Web服务中使用多个后台托管服务

services.AddSingleton<YourServiceType>();
services.AddHostedService<YourServiceType>(p => p.GetRequiredService<YourServiceType>());
services.AddSingleton();
AddHostedService(p=>p.GetRequiredService());

在.Net Core 3.1和.Net 5.0中,您可以通过以下方式获得对托管服务现有实例的引用:

IEnumerable allHostedServices=this.serviceProvider.GetService()

为什么您直接需要服务实例?这是非典型的。您只需注册
IHostedService
实现即可。ASP.NET Core负责实例化和运行它。@ChrisPratt我希望获取HostedService的已配置活动实例的状态,这将是启动/停止的全部目的,我的作用域服务接收由我的HostedService引导的热实例。最终,我只是向我的HostedService添加了一个静态属性以在DI中注册。谢谢您的回答。您的建议,加上Chris Pratt的评论,使我决定将业务逻辑移到流程队列中,并保留托管服务。我不太明白为什么他们选择添加托管服务作为一个暂时的依赖项,但是这个解决方案现在就可以了。非常感谢你的帮助!那边的线程真的很奇怪,我希望这里的每个人都对它发表评论。在dotnet 5中有更好的方法吗?不确定它是如何工作的,但当我运行_serviceProvider.GetService()时;我重新获得托管服务类型。不确定它将如何与多个托管服务一起工作。@也不知道,我不认为您可以证明,除了作为一个一行程序之外,任何原因都可以使用一个一行程序来“更好”。谢谢@AgentFire;)救了我一天
public HubImportClient(IServiceProvider provider)
{
    //This returns null.
    var service = (AbstractBackgroundProcessService<AbstractImportProcess>) provider.GetService(typeof(AbstractBackgroundProcessService<AbstractImportProcess>>));
}
public HubImportClient(IServiceProvider provider)
{
    //This throws an exception, because the service is missing.
    var service = provider.GetRequiredService<AbstractBackgroundProcessService<AbstractImportProcess>>();
}
public HubImportClient(IServiceProvider provider)
{
    //This throws an exception, because the service is missing.
    var service = (AbstractBackgroundProcessService<AbstractImportProcess>) provider.GetRequiredService(typeof(AbstractBackgroundProcessService<AbstractImportProcess>);
}
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;}
}
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;
        }
    }  
}
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;
    }    
}
//This works, but prevents multiple implementations again.
public HubImportClient(IHostedService service)
{
    this.Service = service;   
}
//This does not work again.
public HubImportClient(AbstractBackgroundProcessService<AbstractImportProcess> service)
{
    this.Service = service;   
}
services.AddSingleton<YourServiceType>();
services.AddSingleton<IHostedService>(p => p.GetService<YourServiceType>());
services.AddSingleton<YourServiceType>();
services.AddHostedService<YourServiceType>(p => p.GetRequiredService<YourServiceType>());