Teu*_*man 9 c# asp.net dependency-injection asp.net-core asp.net-core-2.1
我试图使用IHostedService
ASP.NET 2.1中的推荐接口创建后台处理结构。我注册服务如下:
services.AddSingleton<AbstractProcessQueue<AbstractImportProcess>>();
services.AddHostedService<AbstractBackgroundProcessService<AbstractImportProcess>>();
services.AddSignalR();
Run Code Online (Sandbox Code Playgroud)
该AbstractProcessQueue
仅仅是围绕着一个包装BlockingCollection
的,可以入队离队和过程。该AbstractBackgroundProcessService
工具实现IHostedService
接口并查看队列中可以启动的新进程。
现在,当SignalR
我在集线器内部尝试通过这些Dependency Injection
机制获取对后台处理服务的引用时,麻烦就开始了。我已经尝试了以下解决方案,但似乎都无法按预期工作:
public HubImportClient(IServiceProvider provider)
{
//This returns null.
var service = provider.GetService<AbstractBackgroundProcessService<AbstractImportProcess>>();
}
Run Code Online (Sandbox Code Playgroud)
public HubImportClient(IServiceProvider provider)
{
//This returns null.
var service = (AbstractBackgroundProcessService<AbstractImportProcess>) provider.GetService(typeof(AbstractBackgroundProcessService<AbstractImportProcess>>));
}
Run Code Online (Sandbox Code Playgroud)
public HubImportClient(IServiceProvider provider)
{
//This throws an exception, because the service is missing.
var service = provider.GetRequiredService<AbstractBackgroundProcessService<AbstractImportProcess>>();
}
Run Code Online (Sandbox Code Playgroud)
public HubImportClient(IServiceProvider provider)
{
//This throws an exception, because the service is missing.
var service = (AbstractBackgroundProcessService<AbstractImportProcess>) provider.GetRequiredService(typeof(AbstractBackgroundProcessService<AbstractImportProcess>);
}
Run Code Online (Sandbox Code Playgroud)
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;}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
//This works, but prevents multiple implementations again.
public HubImportClient(IHostedService service)
{
this.Service = service;
}
Run Code Online (Sandbox Code Playgroud)
//This does not work again.
public HubImportClient(AbstractBackgroundProcessService<AbstractImportProcess> service)
{
this.Service = service;
}
Run Code Online (Sandbox Code Playgroud)
因此,我的问题仍然存在:我应该如何获得对IHostedService
实现的引用,以便:
(a):我可以注入服务的多个实例,这些实例的类型参数仅不同(例如,针对AbstractImportProcess
es 的托管服务以及针对es 的托管服务AbstractExportProcess
)
(b):IHostedService
该特定类型参数的实例永远只有一个。
在此先感谢您的帮助!
Age*_*ire 22
来自提到的git 页面的当前解决方法:
services.AddSingleton<YourServiceType>();
services.AddSingleton<IHostedService>(p => p.GetService<YourServiceType>());
Run Code Online (Sandbox Code Playgroud)
这会将您的服务创建为托管(在主机启动和关闭时运行和停止),并在您需要的任何地方作为依赖注入。
我不再将此解决方案视为“解决方法”。
相反,我会这样描述它:托管组件和常规服务是不同类型的实体,每个都服务于自己的目的。
然而,上面的解决方案允许将它们组合起来,将托管组件注册为服务,可以在依赖解析链中使用。
这太棒了。
围绕此主题进行了一些讨论。例如,请参阅:https : //github.com/aspnet/Hosting/issues/1489。您将遇到的问题之一是将托管服务添加为临时服务(来自ASP.NET Core 2.1+),这意味着从依赖项注入容器中解析托管服务将每次导致一个新实例。
一般建议是将要与其他服务共享或从其他服务交互的任何业务逻辑封装到特定服务中。查看代码,建议您在AbstractProcessQueue<AbstractImportProcess>
类中实现业务逻辑,并使执行业务逻辑成为的唯一关注点AbstractBackgroundProcessService<T>
。
这只是对@AgentFire 的回答稍作修改。这种方法更清晰,允许在单个 Web 服务中包含多个后台托管服务。
services.AddSingleton<YourServiceType>();
services.AddHostedService<YourServiceType>(p => p.GetRequiredService<YourServiceType>());
Run Code Online (Sandbox Code Playgroud)
您可以直接从IServiceProvider
dotnet core 3.1 及更高版本中获取此信息:
var myHostedService = serviceProvider
.GetServices<IHostedService>()
.OfType<MyHostedService>()
.Single();
Run Code Online (Sandbox Code Playgroud)
这是基于 @andyvan 和 @Hursev 答案的完整解决方案。截至 2022 年,与公认的和最流行的答案相比,这似乎是更“当前”和简洁的解决方法。
//regular implementation of Background/IHostedService. Nothing special.
public class MyBackgroundService : BackgroundService
{
}
//Startup.cs or Program.cs
//Also standard. No extra code required.
services.AddHostedService<MyBackgroundService>();
services.AddTransient<IMyService, MyService>();
//MyService is where we want to consume background servive
public class MyService : IMyService
{
private readonly MyBackgroundService _service;
public MyService(IServiceProvider serviceProvider)
{
_service = serviceProvider.GetServices<IHostedService>().OfType<MyBackgroundService>().Single();
}
public void DoStuff()
{
//Consume background service as any other DI services.
_service.SomethingFromMyBackgroundService();
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2479 次 |
最近记录: |