如何在 .Net Core 3 中引用托管服务?

5

在 .net core 2 中,我创建了一个带有自定义属性的托管服务,例如:

 public class MyService : BackgroundService 
{
public bool IsRunning {get;set;}
...

我可以在startup.cs中进行设置,例如:

public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHostedService,HostedServices.MyService>();
...

然后我可以在Razor页面的其他位置引用它,例如:

public class IndexModel : PageModel
{
    private readonly IHostedService _mySrv;
    public IndexModel(IHostedService mySrv) => _mySrv = mySrv;

    [BindProperty]
    public bool IsRunning { get; set; }

    public void OnGet() => IsRunning = ((HostedServices.MyService)_mySrv).IsRunning;
}

现在我已经升级到 .net core 3,我的启动项已经改变为:

services.AddHostedService<HostedServices.MyService>();

但是,我在IndexModel中使用DI引用时无法获取到我的MyService,它给我返回的是一个类型为GenericWebHostService的对象,而我无法找到如何从中获取我的自定义MyService。在IndexModel中将“IHostedService”更改为“MyService”也不起作用,会出现“无法解析服务”的错误。

我该如何从依赖注入中获取MyService的实例?

1个回答

14

在2.2版本中,您之前的设置大多是由于偶然性而起作用的。每当您注册多个实现来执行一个服务时,最后注册的实现将“获胜”。例如,请看以下代码:

services.AddSingleton<IHostedService, HostedService1>();
services.AddSingleton<IHostedService, HostedService2>();

// ...

public IndexModel(IHostedServie hostedService) { }

被注入到IndexModel中的IHostedService的实现是HostedService2,它是最后注册的。如果IndexModel被更新以接受一个IEnumerable<IHostedService>,它将按照注册顺序获取两个实现:

public IndexModel(IEnumerable<IHostedService> hostedServices) { }

"偶然"的意思是,在你的例子中,只有 HostedServices.MyService 被注册了,所以它也是最后被注册的,因此它“获胜”。

在使用 通用主机(Generic Host) 时(这是 IHostedService 的一种实现),GenericWebHostService 处理 Web 请求,这就会导致问题,因为GenericWebHostServiceHostedServices.MyService 之后注册。希望现在清楚了,这就是为什么在IndexModel 中请求的 IHostedService 不是您预期的原因。

至于解决方案,我建议执行两个注册:

services.AddSingleton<HostedServices.MyService>();
services.AddHostedService(sp => sp.GetRequiredService<HostedServices.MyService>());

然后,更新你的IndexModel来要求你特定的实现:

public IndexModel(HostedServices.MyService myService) { }

这使您可以针对特定的IHostedService实现进行定位。它被注册了两次,针对两种不同的服务类型,但仅创建一个实例。


@KirkLarkin 等等,真的吗?我在哪里可以找到证据呢?因为如果您只将其添加为单例,则不明白谁会调用服务上的 StartAsyncStopAsync。此外,这个答案 似乎与您的说法相矛盾。 - Joelius
1
只要它在IHostedService接口后面进行了注册,它就可以正常工作。这实际上是AddHostedService所做的全部。我会找到一个源代码链接来证明它... - Kirk Larkin
1
@Joelius 这是链接Host 只是请求 IEnumerable<IHostedService> 并在它们上调用 StartAsync。你提供的答案只是说 AddSingleton 而没有指定接口不起作用,这是正确的。我并没有说任何不同。正是我展示的第二个注册将它们联系在一起。 - Kirk Larkin
哦,这是值得知道的事情。文档中有提到吗?我觉得很容易假设它可能不会做同样的事情(尽管它很聪明地做了)。 - Joelius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接