在 Development 环境下依赖注入的举动大概有所差别

打印 上一主题 下一主题

主题 880|帖子 880|积分 2640

奇怪的问题

本周被一个奇怪的问题困扰了一天。事情的起因是如许的:在某个 PR 合并后,我拉了最新代码,但是在我当地F5调试始终报错。示例代码如下:
  1.     public interface Interface1
  2.     {
  3.         void Method1();
  4.     }
  5.     public class MockSerivce
  6.     {
  7.         public MockSerivce(Interface1 interface1)
  8.         {
  9.         }
  10.     }
  11. builder.Services.AddSingleton<MockSerivce>();
复制代码
报的错误呢也显而易见:
  1. Unable to resolve service for type 'DevelopmentTest.Interface1' while attempting to activate 'DevelopmentTest.MockSerivce'
复制代码
我们没有注册 Interface1 到 DI 容器里,那自然实例化 MockSerivce 的时候就找不到依赖了。
但是奇怪的是:我其他同事们都没有这个问题,他们在当地调试的时候都好好的,并不会报错。而且在这个分支编译后的代码在开发服务器上运行的都很完美。
这个就有点冲击到我了,难道是我电脑有问题,VS 有问题,照旧我品行有问题?
寻找答案

当然了代码是不会骗人的,造成以上问题肯定不是我品行问题而是代码的问题。
经过一番尝试,我发现这个问题跟系统运行在哪个环境有关系。只要我把 launchSettings.json 里的   ASPNETCORE_ENVIRONMENT 从 Development 改成别的什么值,那么一切都运行正常了。正巧在我们组其他同事都维护一个自己的 appestings.username.json 然后运行在这个环境之下,也就是说他们都不运行在 Development 下。这就是为啥只有我会报错的缘故原由了。
事情到了这一步,那么我们很容易猜测: .NET DI 系统在 Development 下是有骚操纵的。在 Development 下它会进行依赖分析,如果依赖关系有错误,那么直接会报错。但是在其他环境下就不会提交分析校验,只有在运行时真正尝试实例化对象的时候才会报错。
当然靠猜测总是不太靠谱,干脆翻翻代码吧。很快就找到了:
  1.     internal static ServiceProviderOptions CreateDefaultServiceProviderOptions(HostBuilderContext context)
  2.         {
  3.             bool isDevelopment = context.HostingEnvironment.IsDevelopment();
  4.             return new ServiceProviderOptions
  5.             {
  6.                 ValidateScopes = isDevelopment,
  7.                 ValidateOnBuild = isDevelopment,
  8.             };
  9.         }
复制代码
在 HostingHostBuilderExtensions 这个扩展类里很清楚的看到,只有在 Development 下 DefaultServiceProviderOptions 的 ValidateScopes 与 ValidateOnBuild 会被设置为 True。这就直接证实了上面的猜想。只有在 Development 下才会在启动的时候去校验依赖关系。
强制校验

既然找到了答案,那么让我们来试一下:强制开启依赖关系的校验。
  1. var builder = WebApplication.CreateBuilder(args);
  2. builder.Host.UseDefaultServiceProvider(op =>
  3. {
  4.     op.ValidateOnBuild = true;
  5.     op.ValidateScopes = true;
  6. });
复制代码
代码如上在 Host 上调用 UseDefaultServiceProvider 扩展方法,指定 ValidateScopes 与 ValidateOnBuild 都为 True。
再次运行我们的项目,这个时候不管是在 Development 照旧 Production 照旧别的任何环境下,都会报错了。
  1. Unable to resolve service for type 'DevelopmentTest.Interface1' while attempting to activate 'DevelopmentTest.MockSerivce'
复制代码
总结

通过以上我们可以发现 .NET 的 DI 系统,在 Development 环境下跟其他环境的举动是差别的。在 Development 下会提交进行依赖关系的校验,如果有问题会提前报错。所以我们调试的时候请尽量选择在 Development 下进行或者手动强制开启校验。这个问题很容易被忽视,至少我没在其他博文里见有人提到过。其着实微软的官方文档上是提到了,但也确实就是提了一嘴而已。
关于这个话题其实还没完,还有一个更有意思的问题:Captive dependency 可以聊一下。但是今天太晚了,改天吧。
参考:https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#scope-validation

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

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王柳

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表