为什么ASP.NET Core托管服务的依赖服务需要使用AddScoped()注册?
结论:AddScoped 不是后台托管服务场景下的硬性要求
你把注册方式改成 AddTransient 后正常运行是完全符合预期的,官方示例用 AddScoped 只是出于多场景兼容的考量,不是必须这么写。
核心原理说明
首先要纠正一个普遍存在的认知误区:Scoped 服务的生命周期本质是绑定到 IServiceScope 实例,而非绑定到 HTTP 请求。HTTP 请求场景下你看到的“每个请求对应一个 Scoped 实例”,只是 ASP.NET Core 框架自动给每个请求创建了独立的 IServiceScope 而已,和后台服务里你手动调用 Services.CreateScope() 创建的 Scope 没有本质区别。
官方示例选 AddScoped 的原因
这个示例里的 IScopedProcessingService 默认是按照「多场景共用」的逻辑设计的:如果你的服务既要在控制器(HTTP 请求场景)里调用,又要在后台托管服务里调用,注册成 Scoped 有两个好处:
- HTTP 场景下同一个请求内多次注入该服务,只会初始化一次,比 Transient 性能更好
- 能保证同一个请求内多次注入拿到的是同一个实例,符合绝大多数业务逻辑的预期
你可以根据业务场景自由选择注册方式
如果你的服务只在后台托管服务中使用,完全可以按需选择生命周期:
- 如果你希望同一个手动创建的 Scope 内多次获取该服务,拿到的是同一个实例,就用
AddScoped - 如果你希望每次从服务提供者获取时都新建实例,就用
AddTransient - 如果服务本身是线程安全的、全局单例也满足业务需求,甚至可以用
AddSingleton
唯一的硬性要求
不管你用哪种生命周期注册服务,都不要直接把服务注入到 BackgroundService 的构造函数里。因为 BackgroundService 本身是全局单例,直接注入会导致你注入的服务被提升为单例,和你设定的生命周期预期不符,必须像示例那样手动创建 Scope 后再从 Scope 内的服务提供者获取服务。
内容的提问来源于stack exchange,提问作者Rocklan
相关产品推荐
相关产品推荐

