You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何单个依赖注入作用域内的Scoped服务会被实例化两次?

问题根因

你遇到的是.NET内置依赖注入框架中生命周期不匹配导致的作用域隔离问题,核心逻辑如下:

  • Singleton服务的全局唯一实例是绑定到根服务提供者的,无论你在哪个子作用域第一次触发Singleton的实例化,它的依赖解析都会走根容器逻辑
  • 根容器没有子作用域的上下文,解析Singleton依赖的Scoped服务时,会直接生成一个和根容器生命周期绑定的「根作用域Scoped实例」,这个实例会被Singleton永久持有
  • 你后续在自定义子作用域中单独获取Scoped服务时,会走当前子作用域的缓存逻辑,生成属于当前作用域的全新Scoped实例,因此出现两次实例化输出
执行流程拆解

你的代码实际运行顺序完全符合框架设计:

  1. 调用BuildServiceProvider()生成根服务提供者,此时Singleton未实例化
  2. 创建自定义子作用域,拿到当前作用域的服务提供者scopeProvider
  3. 调用scopeProvider.GetRequiredService<Singleton>():
    • 框架检测到Singleton未实例化,先在根容器中创建Singleton实例
    • 解析Singleton构造参数的Scoped服务,根容器无当前子作用域上下文,生成第一个Scoped实例(输出scoped 1),注入给Singleton
    • Singleton实例化完成,输出singleton 1
  4. 调用scopeProvider.GetRequiredService<Scoped>():
    • 检测当前子作用域缓存中无Scoped实例,生成第二个属于当前作用域的Scoped实例,输出scoped 2
修复方案

如果要实现你预期的「同一个作用域内Scoped仅实例化一次」的效果,可选方案如下:

  • 方案1:取消Scoped服务对Singleton构造函数的直接注入,改为在Singleton中注入IServiceScopeFactory,需要使用Scoped服务时手动创建作用域解析,避免生命周期绑定
  • 方案2:如果该Scoped服务全局仅需一个实例,直接将其注册为Singleton即可
  • 方案3:开启作用域校验,构建服务提供者时传入参数services.BuildServiceProvider(validateScopes: true),此时生命周期不匹配的代码会直接抛出异常,提前暴露逻辑漏洞,避免隐式生成多个实例

内容的提问来源于stack exchange,提问作者Tomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 13:45:01