ServiceProvider

ServiceProvider是我们用来获取服务实例对象的类型,它也是一个特别简单的类型,因为这个类型本身并没有做什么,其实以一种代理模式,其核心功能全部都在IServiceProviderEngine实现类中

ServiceProvider还具有一个扩展类型ServiceProviderServiceExtensions,在扩展类型之中实现了一些我们经常使用的获取服务实例方法,比如GetServices()GetRequiredService()方法,还实现了获取子容器方法CreateScope(),下面来具体的看一下这个类型

从下面代码看到ServiceProvider一个实现了三个接口

  • IServiceProvider 获取服务接口,这个接口是位于System程序集下的,而这个接口只有一个object GetService(Type serviceType)方法,也就是说我们常用很多方法包括泛型获取都是来自于扩展类中
  • IDisposable 说明此对象需要被释放
  • IServiceProviderEngineCallback 这个接口就是检验validateScopes时使用的,接口具有两个方法OnCreate()OnResolve()分别用于创建服务实例时缓存和校验,​
  1. public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback
  2. {}

ServiceProvider这个类型其实挺简单,从下面代码中GetService()方法可以看出它只是代理了一个IServiceProviderEngine实现类型,

_engine: 作为一个IServiceProviderEngine接口,这个接口是ServiceProvider的工作引擎接口,也是一个核心类型,下一章再详细讲解这个接口及其实现类型

_callSiteValidator: 这是一个验证ValidateScopes的缓存类型(访问者模式),可以看到,在构造函数中只有当ValidateScopes为true时才实例化此对象,然后在获取服务实例时通过OnCreate()进行缓存和通过OnResolve()进行校验

ServiceProvider的实例化方式在上一章已经说过,利用ServiceDescriptor集合和ServiceProviderOptions进行实例化,可以看到,在构造方法中首先通过ValidateScopes属性来进行实例化CallSiteValidator和将当前对象赋值给IServiceProviderEngineCallback类型变量

this赋值给IServiceProviderEngineCallback是为了让IServiceProviderEngine进行调用验证

​ 然后通过ServiceProviderMode这个枚举进行判断实例化的具体引擎对象,四个枚举对应四种引擎对象,前面已经说过目前DI只使用了Dynamic这一种,下面说IServiceProviderEngineCallback时也只说这一种

  1. public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback
  2. {
  3. // ServiceProvider工作引擎接口
  4. // 这个接口是一个核心接口
  5. // 使用这个接口的子类进行调用缓存各种注册服务和调用访问者对象进行获取实例对象
  6. private readonly IServiceProviderEngine _engine;
  7. /// 此属性缓存当前注册类型,当ServiceProviderOptions.ValidateScopes为true进行验证
  8. private readonly CallSiteValidator _callSiteValidator;
  9. internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
  10. {
  11. IServiceProviderEngineCallback callback = null;
  12. if (options.ValidateScopes)
  13. {
  14. callback = this;
  15. _callSiteValidator = new CallSiteValidator();
  16. }
  17. // 根据ServiceProviderMode进行实例化对应的工作引擎类型
  18. switch (options.Mode)
  19. {
  20. case ServiceProviderMode.Dynamic:
  21. // 实例化 DynamicServiceProviderEngine
  22. _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback);
  23. break;
  24. case ServiceProviderMode.Runtime:
  25. _engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback);
  26. break;
  27. case ServiceProviderMode.ILEmit:
  28. _engine = new ILEmitServiceProviderEngine(serviceDescriptors, callback);
  29. break;
  30. case ServiceProviderMode.Expressions:
  31. _engine = new ExpressionsServiceProviderEngine(serviceDescriptors, callback);
  32. break;
  33. default:
  34. throw new NotSupportedException(nameof(options.Mode));
  35. }
  36. }
  37. /// 获取指定类型的服务对象
  38. public object GetService(Type serviceType) => _engine.GetService(serviceType);
  39. public void Dispose() => _engine.Dispose();
  40. void IServiceProviderEngineCallback.OnCreate(ServiceCallSite callSite)
  41. =>_callSiteValidator.ValidateCallSite(callSite);
  42. void IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
  43. =>_callSiteValidator.ValidateResolution(serviceType, scope, _engine.RootScope);
  44. }

ServiceProviderServiceExtensions

​ 前面说过这个类是ServiceProvider的扩展类型,提供了更佳便捷,下面就来看看这个这个扩展类提供的方法

​ 在这个扩展类中就扩展了GetRequiredService(),GetServices()CreateScope()三个方法,前两个也是获取服务实例,第三个获取一个子IServiceProvider,也就是说获取一个子容器

GetRequiredService()方法是如果获取的当前类型并没有被注册,那么就会抛出InvalidOperationException异常,从下面代码可以看出,GetRequiredService()方法首先判断当前ServicePrivider是否是ISupportRequiredService的实现类,如果是,则就返回自身的GetRequiredService()方法,如果不是,就直接调用GetService(),如果返回服务实例为NULL,就抛出异常.

ISupportRequiredService接口中只定义了GetRequiredService(),然而现在的ServiceProvider类型并没有实现ISupportRequiredService接口

GetServices()方法是获取当前类型的所有服务实例,可以看到这个方法无非是调用的GetRequiredService(),只不过参数是一个IEnumerable集合,在内部使用IEnumerable参数获取服务实例是一个特殊处理,这个在后面就可以看到

CreateScope()方法是一个获取子类容器的,获取方式从下面代码看的也是通过服务注册的方式获取服务实例,也就是说内部进行了注册,这个注册是在ServiceProviderEngine类中

  1. public static class ServiceProviderServiceExtensions
  2. {
  3. // 泛型重载
  4. public static T GetService<T>(this IServiceProvider provider)
  5. => (T)provider.GetService(typeof(T));
  6. // 如果当前服务并未注册,则会抛出异常
  7. public static object GetRequiredService(this IServiceProvider provider, Type serviceType)
  8. {
  9. // 如果当前ServiceProvider实现了 ISupportRequiredService
  10. // 则直接调用当前ServiceProvier的GetRequiredService获取服务实例
  11. var requiredServiceSupportingProvider = provider as ISupportRequiredService;
  12. if (requiredServiceSupportingProvider != null)
  13. return requiredServiceSupportingProvider.GetRequiredService(serviceType);
  14. // 如果当前ServiceProvider未实现ISupportRequiredService
  15. // 就直接调用GetService获取服务实例,但是如果服务实例为空,则抛出异常
  16. var service = provider.GetService(serviceType);
  17. if (service == null)
  18. throw new InvalidOperationException(Resources.FormatNoServiceRegistered(serviceType));
  19. return service;
  20. }
  21. // 泛型版本
  22. public static T GetRequiredService<T>(this IServiceProvider provider)
  23. => (T)provider.GetRequiredService(typeof(T));
  24. // 获取指定注册类型<T>的所有服务实例
  25. public static IEnumerable<T> GetServices<T>(this IServiceProvider provider)
  26. => provider.GetRequiredService<IEnumerable<T>>();
  27. // 同上,
  28. public static IEnumerable<object> GetServices(this IServiceProvider provider, Type serviceType)
  29. {
  30. // 制造一个serviceType类型的IEnumberable<>集合,serviceTypele类型作为当前集合的泛型参数
  31. var genericEnumerable = typeof(IEnumerable<>).MakeGenericType(serviceType);
  32. return (IEnumerable<object>)provider.GetRequiredService(genericEnumerable);
  33. }
  34. // 创建一个子IServiceProvider实例
  35. // 内部其实将IServiceScopeFactory接口和一个ServiceScopeFactoryCallSite进行了注册
  36. // 这个是在IServiceProviderEngine的实现类ServiceProviderEngine中的,以后在详细介绍
  37. public static IServiceScope CreateScope(this IServiceProvider provider)
  38. => provider.GetRequiredService<IServiceScopeFactory>().CreateScope();
  39. }

Core官方DI解析(2)-ServiceProvider的更多相关文章

  1. Core官方DI剖析(1)--ServiceProvider类和ServiceCollection类

    前段时间看了蒋老师的Core文章,对于DI那一块感觉挺有意思,然后就看了一下Core官方DI的源码,这也算是第一个看得懂大部分源码的框架,虽然官方DI相对来说特别简单, 官方DI相对于其它框架(例如 ...

  2. Core官方DI解析(3)-ServiceCallSite.md

    上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么东西,因为这个类型其实都是调用的其它对象 ...

  3. Core官方DI解析(4)--CallSiteRuntimeResolver

    ​ CallSiteRuntimeResolver类型是一个创建或获取服务实例的类型,这个类型继承了CallSiteVisitor<TArgument, TResult>这个类型,也是使用 ...

  4. Core官方DI解析(5)-ServiceProviderEngine

    最后来看看前面一直说的Engine(工作引擎),工作引擎接口是IServiceProviderEngine在ServiceProvider的构造函数中看到了根据指定的Mode创建了不同的实现类,下面先 ...

  5. abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析

    老版Abp对Castle的严重依赖在vnext中已经得到了解决,vnext中DI容器可以任意更换,为了实现这个功能,底层架构相较于老版abp,可以说是进行了高度重构.当然这得益于.Net Core的D ...

  6. Asp.Net Core中DI的知识总结

    在asp.net core中DI的概念是由这几部分组成的: IServiceCollection,保存IServiceDescriptor实例的列表 IServiceProvider,只有一个方法Ge ...

  7. asp.net core的DI框架思考以及服务实例的获取方式总结

    转载请注明出处: https://home.cnblogs.com/u/zhiyong-ITNote/ 整个asp.net core管道从WebHostBuilder到WebHost到后续请求的类中, ...

  8. 实战Asp.Net Core:DI生命周期

    title: 实战Asp.Net Core:DI生命周期 date: 2018-11-30 21:54:52 --- 1.前言 Asp.Net Core 默认支持 DI(依赖注入) 软件设计模式,那使 ...

  9. 阅读DMA Controller Core 官方手册

    阅读DMA Controller Core 官方手册 DMA控制器框架图 怎样去设定一个DMA控制器 实例化DMA控制器 参数配置界面如下图所示: 对于width of the DMA length ...

随机推荐

  1. MYSQL如何计算两个日期间隔天数

    如何透过MYSQL自带函数计算给定的两个日期的间隔天数   有两个途径可获得   1.利用TO_DAYS函数   select to_days(now()) - to_days('20120512') ...

  2. 【TensorFlow篇】--反向传播

    一.前述 反向自动求导是 TensorFlow 实现的方案,首先,它执行图的前向阶段,从输入到输出,去计算节点值,然后是反向阶段,从输出到输入去计算所有的偏导. 二.具体 1.举例 图是第二个阶段,在 ...

  3. ASP.NET Core中使用GraphQL - 第七章 Mutation

    ASP.NET Core中使用GraphQL - 目录 ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中间 ...

  4. FragmentTabHostBottomDemo【FragmentTabHost + Fragment实现底部选项卡】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 使用FragmentTabHost实现底部选项卡效果. 备注:该Demo主要是演示FragmentTabHost的一些设置和部分功能 ...

  5. 不使用 webpack,vuejs 异步加载模板

    webpack 打包不会玩,整了这么个小玩具 一段 vue 绑定代码,关键点在 gmallComponent 1.异步加载外部 vue 文件(非 .vue) 2.按一定规则拆分 template.sc ...

  6. 一个多阶段库存订货问题的 +Leapms 求解要点

    一个多阶段库存订货问题的 +Leapms 求解要点 问题来自微信公众号“运筹分享交流”——“互助·运筹擂台3 多阶段库存订货问题”. 数学概念模型 求解结果 +Leapms>mip relexe ...

  7. Python实战171202元组访问

    学生信息系统中数据为固定格式: (名字,年龄,性别,邮箱地址,......) 学生数量很大为了减小存储开销,对每个学生信息用元组表示: ('jim',18,'male','jim8765@gmail. ...

  8. Django-restframework之路由控制、解析器及响应器

    django-restframework之路由控制.解析器及响应器 一 前言 本篇博客介绍 restframework 框架的剩下几个组件,路由控制有三种:传统路由.半自动路由及全自动路由:解析器是用 ...

  9. [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(一)

    一步步打造一个简单的 MVC 电商网站 - BooksStore(一) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore &l ...

  10. vs2017和vs2019专业版和企业版

    步骤:打开vs2017,依次点击--->帮助----->注册产品 专业版: Professional: KBJFW-NXHK6-W4WJM-CRMQB-G3CDH 企业版: Enterpr ...