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

How to reference a hosted service in .Net Core 3?

回到 .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' 也不起作用,我收到 'Unable to resolve service' 错误。

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

在 2.2 中,您使用的设置大部分是偶然的。每当您针对一项服务注册多个实现时,最后注册的就是 "wins"。例如,取下面的代码:

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

// ...

public IndexModel(IHostedServie hostedService) { }

注入 IndexModelIHostedService 的实现是 HostedService2;最后注册的。如果要更新 IndexModel 以采用 IEnumerable<IHostedService>,它将获得 both 实现,按注册顺序:

public IndexModel(IEnumerable<IHostedService> hostedServices) { }

当我说 "by chance" 时,我的意思是在您的示例中,只有 HostedServices.MyService 被注册,所以它也是最后注册的,因此它"wins".

在 3.0 中,当使用 Generic Host 时,IHostedServiceGenericWebHostService 的实现负责处理 Web 请求。这会给您带来问题,因为 GenericWebHostServiceHostedServices.MyService 之后被注册 。我希望现在已经清楚了,这就是为什么您在 IndexModel 中请求的 IHostedService 不是您所期望的。

在解决方案方面,我建议执行两次注册:

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

然后,更新您的 IndexModel 以要求您的具体实施:

public IndexModel(HostedServices.MyService myService) { }

这允许您针对 IHostedService 的具体实施。针对两种不同的服务类型注册了两次,但只创建了一个实例。