qidao123.com技术社区-IT企服评测·应用市场

标题: .NET 依赖注入中的 Captive Dependency [打印本页]

作者: 我爱普洱茶    时间: 2025-1-10 02:38
标题: .NET 依赖注入中的 Captive Dependency
各人好,上一篇我们分析了 .NET 依赖注入的默认行为,实在呢还没完全讲完。今天我先给各人出一道题:
  1.     public interface IDbContext
  2.     {
  3.     }
  4.     public class SqlServerDbContext : IDbContext
  5.     {
  6.     }
  7.     public class LongTermSerive : BackgroundService
  8.     {
  9.         private readonly IDbContext _context;
  10.         public LongTermSerive(IDbContext context)
  11.         {
  12.             _context = context;
  13.         }
  14.         protected override Task ExecuteAsync(CancellationToken stoppingToken)
  15.         {
  16.             return Task.CompletedTask;
  17.         }
  18.     }
复制代码
  1. builder.Services.AddScoped<IDbContext, SqlServerDbContext>();
  2. builder.Services.AddHostedService<LongTermSerive>();
复制代码
请问以上服务的注册有没有题目?
认识 .NET 的同学很快就会说:这当然有题目,IDbContext 是 Scope 生命周期,LongTermSerive 因为注册成了 HostedService 所以现实上它是 Singleton 生命周期。Singleton 不能持有 Scope 生命周期的服务。说的更通用一点的话就是:生命周期长的服务无法依赖生命周期比它的服务。
真的是这样吗???
以上回复只说对了一半。这时候肯定马上会有同学跳出来说,“这怎么会不对呢?我刚刚都试过了,VS直接报错了”。
  1. System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: DevelopmentTest.LongTermSerive': Cannot consume scoped service 'DevelopmentTest.IDbContext' from singleton
复制代码
不要发急让我们继续分析下去。
Captive Dependency

首先让我们澄清一个概念。像以上这种情况:当生命周期长(Singleton)的服务持有生命周期短(Scope)的服务的时候我们叫做 "Captive Dependency"(Transient不在讨论范围内)。
不知道怎么翻译成中文比较符合。微软的文档上翻译作"捕获依赖",个人认为不太恰当。
"Captive Dependency" 会带来什么题目?
.NET DI 支持 Captive Dependency 吗?

当我们了解这个概念后,上面的题目可以转换成 " .NET DI 支持 Captive Dependency 吗?"。
根据上一次我们的文章的内容,我们知道 .NET DI 的行为是跟所在的环境有关系的。所以讨论这个题目我们还是要分开来对待:
总结

现在我们可以作一个总结:
.NET DI 是支持 Captive Dependency 的,但是在 Development 环境下或者手动开启 ValidateScopes = true 的时候它不支持,它会阻止 Captive Dependency。换句话说 .NET DI 在阻止 Captive Dependency 上只做了一半的工作,并不能 100% 确保不发生 Captive Dependency。开发者们在写代码的时候还是要自己注意了,不能完全依赖 .NET 的检测。
关于这个题目,我也在 .NET Runtime 的 Repository 下开了一个 ticket 举行讨论。微软给出的理由是基于性能的考虑,生产环境这个校验默认不开启。实在我个人觉得微软应该不管在什么环境下都默认开启校验,尽可能的制止 Captive Dependency。因为 90% 的项目实在并不在乎这点性能开销。如果你的应用步调真的很在乎性能那么可以手动关闭这个校验,这个时候开发者自己需要完全对这个依赖关系负责。
https://blog.ploeh.dk/2014/06/02/captive-dependency/
https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines#captive-dependency
https://github.com/dotnet/runtime/discussions/109491

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4