在上一篇文章中,我们学习了Microsoft.Extensions.DependencyInjection中的IServiceCollection,包括服务注册转换为ServiceDescriptors,然后添加到集合中。

探索 .NET Core 依赖注入的 IServiceCollection[1]

在本文中,我们会学习 IServiceProvider,了解它是什么,以及它是怎么创建出来的,我们将根据上一篇文章中创建的IServiceCollection来学习如何构建IServiceProvider。

什么是 IServiceProvider?

IServiceProvider会根据程序的要求在运行时解析服务类型的实例,ServiceProvider来保证已解析的服务在预期的生命周期内有效,这个实现设计的非常高效,所以服务的解析速度非常快。

构建一个 IServiceProvider

首先,当我们把服务都添加到 IServiceCollection ,接下来会构建一个IServiceProvider, 它能够提供我们程序中所依赖服务的实例,本质上它包装了 IServiceCollection。

通过调用 BuildServiceProvider(IServiceCollection上的一个扩展方法)完成构建:

var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ClassA>();
serviceCollection.AddSingleton<IThing, ClassB>();var serviceProvider = serviceCollection.BuildServiceProvider();

当我们没有传入任何参数时,它会创建一个 ServiceProviderOptions 的一个默认实例:

public static class ServiceCollectionContainerBuilderExtensions
{ public static ServiceProvider BuildServiceProvider(this IServiceCollection services){return services.BuildServiceProvider(ServiceProviderOptions.Default);}

ServiceProviderOptions 有两个属性,在本文后边的内容,我会详细介绍这些:

public class ServiceProviderOptions
{public bool ValidateScopes { get; set; }public bool ValidateOnBuild { get; set; }
}

BuildServiceProvider 的方法内部是这样的:

public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options)
{if (services == null){throw new ArgumentNullException(nameof(services));}if (options == null){throw new ArgumentNullException(nameof(options));}IServiceProviderEngine engine;
#if !NETCOREAPPengine = new DynamicServiceProviderEngine(services);
#elseif (RuntimeFeature.IsDynamicCodeCompiled){engine = new DynamicServiceProviderEngine(services);}else{// Don't try to compile Expressions/IL if they are going to get interpretedengine = new RuntimeServiceProviderEngine(services);}
#endifreturn new ServiceProvider(services, engine, options);
}

最终,它会创建并返回一个 ServiceProvider。

ServiceProviderEngine

在上面的代码中,ServiceProvider选择应该使用哪个 engine, engine 是一个组件,它的功能是负责 DI容器中服务实例的创建,然后把实例注入到其他服务中。

这些是 IServiceProviderEngine 的四个实现:

•Dynamic•Runtime•ILEmit•Expressions (System.Linq.Expressions)

从上面的代码中,我们可以看到在大多数情况下会使用 DynamicServiceProviderEngine,仅在目标框架不支持动态代码编译的情况下,才使用RuntimeServiceProviderEngine,DynamicServiceProviderEngine 会使用 ILEmit 或者 Expressions 来解析服务。

我们看一下 ServiceProviderEngine 的构造函数的内容:

protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors)
{_createServiceAccessor = CreateServiceAccessor;Root = new ServiceProviderEngineScope(this);RuntimeResolver = new CallSiteRuntimeResolver();CallSiteFactory = new CallSiteFactory(serviceDescriptors);CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite());RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
}

它创建一个 Root ServiceProviderEngineScope,然后传入this, scopes限制了服务的生命周期,最常见的就是,.Net Core 收到一个接口请求时,它创建的服务就是 Scope 类型。

这种情况下,我们注册的单例服务,它都是从 Root Scope 返回的。

然后创建一个 CallSiteRuntimeResolver,我会在接下来的文章介绍它。

最后,在上面的构造函数中,将创建一个新的ConcurrentDictionary来保存有关服务的信息,按需设计,只有开始使用这些服务时,它才会开始创建,如果有些服务注册了,但是没有使用的话,那么它永远不会创建。

ServiceProvider 构造方法

让我们回到 BuildServiceProvider 方法的最后一行,它会传入 IServiceCollection, Engine和ServiceProviderOptions:

internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngine engine, ServiceProviderOptions options)
{_engine = engine;if (options.ValidateScopes){_engine.InitializeCallback(this);_callSiteValidator = new CallSiteValidator();}if (options.ValidateOnBuild){List<Exception> exceptions = null;foreach (ServiceDescriptor serviceDescriptor in serviceDescriptors){try{_engine.ValidateService(serviceDescriptor);}catch (Exception e){exceptions = exceptions ?? new List<Exception>();exceptions.Add(e);}}if (exceptions != null){throw new AggregateException("Some services are not able to be constructed", exceptions.ToArray());}}
}

在上面的代码中,我们可以看到在构造函数中使用了ServiceProviderOptions, 当ValidateScopes为true时,ServiceProvider会传入this调用 engine 的 InitializeCallback方法,它还创建一个新的CallSiteValidator。

如果 ValidateOnBuild 为true的话,它会检查DI容器中已注册的所有服务,遍历了ServiceDescriptor 集合,然后调用 ValidateService, 检查服务,并且这里捕获了异常,如果有错误,会抛出一个聚合的异常信息。

那么在程序中使用 ValidateOnBuild,可以保证在程序启动时就检查已注册的错误服务,而不是在首次解析服务时在运行时捕获异常,这个可以很好的帮助排除问题。

ValidateService 的方法内部如下:

public void ValidateService(ServiceDescriptor descriptor)
{if (descriptor.ServiceType.IsGenericType && !descriptor.ServiceType.IsConstructedGenericType){return;}try{ServiceCallSite callSite = CallSiteFactory.GetCallSite(descriptor, new CallSiteChain());if (callSite != null){_callback?.OnCreate(callSite);}}catch (Exception e){throw new InvalidOperationException($"Error while validating the service descriptor '{descriptor}': {e.Message}", e);}
}

总结

在本文中,我们重点介绍了如何从IServiceCollection来构建IServiceProvider,我们探索了一些实现细节,以了解如何应用ValidateScopes和ValidateOnBuild ServiceProviderOptions,我们在这篇文章中谈到了很多内部代码,但作为库的使用者,您不必担心这些细节。

最重要的一点是,在IServiceCollection上调用BuildServiceProvider之后,将创建默认的ServiceProvider。

var serviceProvider = serviceCollection.BuildServiceProvider();

也可以传入 ServiceProviderOptions

var serviceProviderWithOptions = serviceCollection.BuildServiceProvider(new ServiceProviderOptions
{ValidateOnBuild = true,ValidateScopes = true
});

原文链接: https://www.stevejgordon.co.uk/aspnet-core-dependency-injection-what-is-the-iserviceprovider-and-how-is-it-built[2]

最后

欢迎扫码关注我们的公众号 【全球技术精选】,专注国外优秀博客的翻译和开源项目分享,也可以添加QQ群 897216102

探索 .NET Core 依赖注入的 IServiceProvider相关推荐

  1. 探索 .NET Core 依赖注入的 IServiceCollection

    如果您使用了.NET Core,则很可能已使用Microsoft.Extensions.DependencyInjection中的内置依赖项注入容器,在本文中,我想更深入地了解Microsoft De ...

  2. everythingtoolbar.dll”或它的一个依赖项。_ASP.NET Core依赖注入最佳实践、提示和技巧...

    译者前言 本文译自ABP框架的开发博客<ASP.NET Core Dependency Injection Best Practices, Tips & Tricks>一文(原作者 ...

  3. ASP.NET Core依赖注入最佳实践,提示技巧

    分享翻译一篇Abp框架作者(Halil İbrahim Kalkan)关于ASP.NET Core依赖注入的博文. 在本文中,我将分享我在ASP.NET Core应用程序中使用依赖注入的经验和建议. ...

  4. ASP.NET Core依赖注入深入讨论

    这篇文章我们来深入探讨ASP.NET Core.MVC Core中的依赖注入,我们将示范几乎所有可能的操作把依赖项注入到组件中. 依赖注入是ASP.NET Core的核心,它能让您应用程序中的组件增强 ...

  5. .net core依赖注入

    .net core依赖注入小结 #依赖注入介绍 .net core 中依赖注入是必不可少的一项必学内容,官方介绍为:依赖注入是一种软件设计模式,指一个或多个依赖(或服务)被注入,或通过引用传递,传入一 ...

  6. .Net Core 依赖注入

    .Net Core 依赖注入 为什么要使用依赖注入框架 .Net Core DI 核心类 三种生命周期 服务注册 单例注册 作用域注册 瞬时注册 直接注入实例 工厂模式注册 注册不同实例 尝试注册 移 ...

  7. ASP.NET Core依赖注入容器中的动态服务注册

    介绍 在ASP.NET Core中,每当我们将服务作为依赖项注入时,都必须将此服务注册到ASP.NET Core依赖项注入容器.但是,一个接一个地注册服务不仅繁琐且耗时,而且容易出错.因此,在这里,我 ...

  8. 【ASP.NET Core】ASP.NET Core 依赖注入

    一.什么是依赖注入(Denpendency Injection) 这也是个老身常谈的问题,到底依赖注入是什么? 为什么要用它? 初学者特别容易对控制反转IOC(Iversion of Control) ...

  9. 全面理解 ASP.NET Core 依赖注入

    DI在.NET Core里面被提到了一个非常重要的位置, 这篇文章主要再给大家普及一下关于依赖注入的概念,身边有工作六七年的同事还个东西搞不清楚.另外再介绍一下.NET  Core的DI实现以及对实例 ...

最新文章

  1. Linux ROS与嵌入式的串口通信
  2. ai字体素材网站_4个网站,涵盖几乎所有素材,字体、设计、图片各种资源管够...
  3. So easy!Nginx+SpringBoot 实现负载均衡
  4. git/码云上关于项目的一些操作:初始化、克隆、上传修改等
  5. 【MATLAB统计分析与应用100例】案例007:matlab数据的极差归一化变换
  6. mysql 分组查询原理,MySQL分組查詢Group By實現原理詳解
  7. android中的多媒体应用camera
  8. 【脑机接口】用人脑意念控制机器人即将落地
  9. c语言lua读文件,file-io – 在Lua中逐行读取文件
  10. js实现放大镜的效果
  11. 直播、线上办公、IoT需求井喷,Wi-Fi 6如何防止网络“塞车”?
  12. Selenium-鼠标操作
  13. 【UNITY3D 游戏开发之八】UNITY编译到IPHONE运行 COLLIDER 无法正常触发事件解决方案...
  14. 中国气象局发布实施细则 推进气象数据安全合规有序开放共享
  15. 软件项目经理应具备的素质和条件_一个合格的软件项目经理应该具备哪些条件?...
  16. 最新版微型商城2.0版网站源码 带有一键安装
  17. 说一说协议生成器 - Ricequant米筐量化
  18. 谷歌联网断网都可以玩的恐龙小游戏(内容有不死加速挂)
  19. 邮件在线编辑器-零基础制作精美图文并茂的HTML邮件不费力
  20. N卡自带录屏软件geforce 双屏录制问题

热门文章

  1. 自动调试自动编译五分钟上手
  2. Educational Codeforces Round 1
  3. sublime快捷键收藏
  4. 学习笔记之卸载远程目标进程中的DLL模块(转)
  5. 页面上指定类型的控件的样式添加
  6. jq select操作全集
  7. JavaScript组件之JQuery(A~Z)教程(基于Asp.net运行环境)[示例代码下载](一)
  8. 高人写的浙大简史(转)
  9. 火狐 增强查找工具栏_在“提示”框中:简单的IE至Firefox同步,轻松的Windows工具栏和识别USB电缆...
  10. 超链接禁用_在Microsoft Word 2003和2007中禁用自动超链接