如何在 .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) { }
注入 IndexModel
的 IHostedService
的实现是 HostedService2
;最后注册的。如果要更新 IndexModel
以采用 IEnumerable<IHostedService>
,它将获得 both 实现,按注册顺序:
public IndexModel(IEnumerable<IHostedService> hostedServices) { }
当我说 "by chance" 时,我的意思是在您的示例中,只有 HostedServices.MyService
被注册,所以它也是最后注册的,因此它"wins".
在 3.0 中,当使用 Generic Host 时,IHostedService
、GenericWebHostService
的实现负责处理 Web 请求。这会给您带来问题,因为 GenericWebHostService
在 HostedServices.MyService
之后被注册 。我希望现在已经清楚了,这就是为什么您在 IndexModel
中请求的 IHostedService
不是您所期望的。
在解决方案方面,我建议执行两次注册:
services.AddSingleton<HostedServices.MyService>();
services.AddHostedService(sp => sp.GetRequiredService<HostedServices.MyService>());
然后,更新您的 IndexModel
以要求您的具体实施:
public IndexModel(HostedServices.MyService myService) { }
这允许您针对 IHostedService
的具体实施。针对两种不同的服务类型注册了两次,但只创建了一个实例。
回到 .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) { }
注入 IndexModel
的 IHostedService
的实现是 HostedService2
;最后注册的。如果要更新 IndexModel
以采用 IEnumerable<IHostedService>
,它将获得 both 实现,按注册顺序:
public IndexModel(IEnumerable<IHostedService> hostedServices) { }
当我说 "by chance" 时,我的意思是在您的示例中,只有 HostedServices.MyService
被注册,所以它也是最后注册的,因此它"wins".
在 3.0 中,当使用 Generic Host 时,IHostedService
、GenericWebHostService
的实现负责处理 Web 请求。这会给您带来问题,因为 GenericWebHostService
在 HostedServices.MyService
之后被注册 。我希望现在已经清楚了,这就是为什么您在 IndexModel
中请求的 IHostedService
不是您所期望的。
在解决方案方面,我建议执行两次注册:
services.AddSingleton<HostedServices.MyService>();
services.AddHostedService(sp => sp.GetRequiredService<HostedServices.MyService>());
然后,更新您的 IndexModel
以要求您的具体实施:
public IndexModel(HostedServices.MyService myService) { }
这允许您针对 IHostedService
的具体实施。针对两种不同的服务类型注册了两次,但只创建了一个实例。