我试图使用ASP.NET 2.1中推荐的IHostedService
接口创建后台处理结构。我注册了以下服务:
services.AddSingleton<AbstractProcessQueue<AbstractImportProcess>>();
services.AddHostedService<AbstractBackgroundProcessService<AbstractImportProcess>>();
services.AddSignalR();
AbstractProcessQueue
只是围绕BlockingCollection
可以排队和出队的进程的包装。 AbstractBackgroundProcessService
实现IHostedService
接口,并在队列中查找可以启动的新进程。
现在,当我在SignalR
集线器中尝试通过Dependency Injection
机制获取对后台处理服务的引用时,麻烦就开始了。我已经尝试了以下解决方案,但似乎都无法按预期工作:
public HubImportClient(IServiceProvider provider)
{
//This returns null.
var service = provider.GetService<AbstractBackgroundProcessService<AbstractImportProcess>>();
}
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;
}
因此,我的问题仍然是:我应该如何获得对IHostedService
实现的引用,以便:
(a):我可以注入服务的多个实例,这些实例的类型参数仅不同(例如,AbstractImportProcess
es的托管服务以及AbstractExportProcess
es的托管服务)
(b):该特定类型参数的IHostedService
实例只有一个。
在此先感谢您的帮助!
答案 0 :(得分:5)
这只是对@AgentFire 的回答稍作修改。这种方法更清晰,并且允许在单个 Web 服务中包含多个后台托管服务。
services.AddSingleton<YourServiceType>();
services.AddHostedService<YourServiceType>(p => p.GetRequiredService<YourServiceType>());
答案 1 :(得分:4)
围绕该主题进行了一些讨论。例如,请参见:https://github.com/aspnet/Hosting/issues/1489。您将遇到的问题之一是将托管服务添加为临时服务(来自ASP.NET Core 2.1+),这意味着从依赖项注入容器中解析托管服务每次都会导致一个新实例。 / p>
一般建议是将要与其他服务共享或从其他服务交互的任何业务逻辑封装到特定服务中。查看代码,建议您在AbstractProcessQueue<AbstractImportProcess>
类中实现业务逻辑,并使执行业务逻辑成为AbstractBackgroundProcessService<T>
的唯一关注点。
答案 2 :(得分:0)
提到的git page的当前解决方法:
services.AddSingleton<YourServiceType>();
services.AddSingleton<IHostedService>(p => p.GetService<YourServiceType>());
这会将您的服务创建为托管服务(在主机启动和关闭时运行和停止),并在您需要的任何地方作为注入注入服务。
答案 3 :(得分:0)
在 .Net Core 3.1 和 .Net 5.0 中,您可以通过以下方式获取对托管服务的现有实例的引用:
IEnumerable<IHostedService> allHostedServices = this.serviceProvider.GetService<IEnumerable<IHostedService>>();