.NET Core依赖注入到托管服务的转换

9
我的.NET Core应用程序需要在指定的时间间隔内爬取数据。我选择使用实现它与API并行运行。托管服务需要注入一些服务。我在中注册它们,但是我收到了一个错误信息:

System.InvalidOperationException: 'Cannot consume scoped service 'IXService' from singleton 'Microsoft.AspNetCore.Hosting.Internal.HostedServiceExecutor'.'

我的startup.cs:
services.AddScoped<IXService, XService>();
services.AddHostedService<MyHostedService>();

我曾经遇到过类似的 DbContext 问题,但是在 https://dev59.com/DFYM5IYBdhLWcg3wxicy#48368934 上找到了解决方法。然而这一次我需要依赖注入深层次的组件,每个组件都使用 IServiceScopeFactory 处理看起来不是一个优雅的解决方案。


1
我不理解。如果您可以解决DbContext的问题,那么为什么不能为MyHostedService需要的所有其他服务解决它呢? - Camilo Terevinto
“似乎没有优雅的解决方案”,假设我有许多需要深入注入的服务,每个服务在构造函数中都会消耗其他服务。这种解决方案会导致额外的代码行数和使用行数,而标准的依赖注入只需要几行代码来注册服务,然后将它们包含在构造函数的参数中,这样更加清晰明了。 - Michal Rosenbaum
你接受了那个重复的答案,它来自你在问题中发布的链接? - Camilo Terevinto
1个回答

15
由于 MyHostedService 具有单例生命周期,比作用域生命周期更长,所以不允许这样做。基本的假设是,注册为作用域的服务不应该无限期地保持活动状态,如果单例服务保持对作用域服务的引用,则很容易发生这种情况。
我认为你正在寻找的解决方案是将 IServiceProvider 注入 MyHostedService,使用它创建一个新的作用域和新的 XService 实例,每当需要时使用它。
也就是说,替换原来的实现。
_xService.Foo();

using(var scope = _serviceProvider.CreateScope()) {
    var xService = scope.ServiceProvider.GetService<IXService>();
    xService.Foo();
}

当然,另一种方法就是将XService注册为单例,只需将AddScoped调用替换为AddSingleton,但我不建议这样做。

编辑:在发布我的回复之前,我必须承认我没有阅读您的链接。然而,我仍然认为这是最优雅的解决方案。


2
这并不完全正确。AddHostedService<T>将它们添加为瞬态,但它们只由HostedServiceExecutor创建一次。https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting.internal.hostedserviceexecutor?view=aspnetcore-2.1. - alsami
谢谢您的纠正,我误读了错误信息。它明确指出是HostedServiceExecutor。 - Håkon Kaurel
2
仅供更新。在2018年11月,代码被更改为注册为单例,这非常重要。它允许其他请求将托管服务作为单例检索。请参见AspNetCore /#4147在github上使AddHostedService注册单例https://github.com/dotnet/extensions/commit/75c680d686504552e5ddde047400a165f2f70be2 - SOHO Developer

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