到目前为止,我们定义的ServiceProvider已经实现了基本的服务提供和回收功能,但是依然漏掉了一些必需的细节特性。这些特性包括如何针对IServiceProvider接口提供一个ServiceProvider对象,何创建ServiceScope,以及如何提供一个服务实例的集合。

一、提供一个ServiceProvider对象

我们知道当将服务类型指定为IServiceProvider接口并调用ServiceProvider的GetService方法是,ServiceProvider对象本身将会作为服务实例返回,这个特性可以利用一个自定义的Service来实现。如下面的代码片段所示,我们定义的这个ServiceProviderService既是一个Service,又是一个ServiceCallSite。它默认采用生命周期管理模式为Scoped,在Invoke和Build方法中,它直接将当前ServiceProvider作为提供的服务实例。在初始化ServiceTable的时候,我们额外添加一个针对ServiceProviderService的ServideEntry。

   1: internal class ServiceProviderService : IService, IServiceCallSite

   2: {

   3:     public ServiceLifetime Lifetime => ServiceLifetime.Scoped;

   4:     public IService Next { get; set; }

   5:  

   6:     public Expression Build(Expression provider)

   7:     {

   8:         return provider;

   9:     }

  10:  

  11:     public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)

  12:     {

  13:         return this;

  14:     }

  15:  

  16:     public object Invoke(ServiceProvider provider)

  17:     {

  18:         return provider;

  19:     }

  20: }

  21:  

  22: internal class ServiceTable

  23: {

  24:     public ServiceTable(IServiceCollection services)

  25:     {

  26:         //解析ServiceCollection并添加相应ServiceEntry

  27:         this.ServieEntries[typeof(IServiceProvider)] = new ServiceEntry(new ServiceProviderService());

  28:     }

  29: }

二、创建ServiceScope

创建ServiceScope的目的在于创建作为当前ServiceProvider儿子的另一个ServiceProvider,新创建的ServiceProvider不仅与原来的ServiceProvider具有相同的根,同时共享所有的服务注册信息。利用这个新的ServiceProvider来代替现有的ServiceProvider,其主要的目的还是使我们能够及时地回收提供的服务实例。ServiceScope是通过它的工厂ServiceScopeFactory来创建的,所以先创建了如下一个ServiceScopeFactory类和对应的ServiceScope,它们的定义与我们在前面一节介绍的完全一致。

   1: internal class ServiceScope : IServiceScope

   2: {

   3:     public IServiceProvider ServiceProvider { get; private set; }

   4:  

   5:     public ServiceScope(ServiceProvider serviceProvider)

   6:     {

   7:         this.ServiceProvider = serviceProvider;

   8:     }

   9:  

  10:     public void Dispose()

  11:     {

  12:         (this.ServiceProvider as IDisposable)?.Dispose();

  13:     }

  14: }

  15:  

  16: internal class ServiceScopeFactory : IServiceScopeFactory

  17: {

  18:     public ServiceProvider ServiceProvider { get; private set; }

  19:  

  20:     public ServiceScopeFactory(ServiceProvider serviceProvider)

  21:     {

  22:         this.ServiceProvider = serviceProvider;

  23:     }

  24:  

  25:     public IServiceScope CreateScope()

  26:     {

  27:         return new ServiceScope(this.ServiceProvider);

  28:     }

  29: }

  30:  

  31: internal class ServiceProvider : IServiceProvider, IDisposable

  32: {

  33:     

  34:     public ServiceProvider(ServiceProvider parent)

  35:     {

  36:         this.Root = parent.Root;

  37:         this.ServiceTable = parent.ServiceTable;

  38:     }

  39: }

为了让ServiceProvider的GetService方法在服务类型指定为IServiceScopeFactory接口的时候能够自动返回上面我们定义的ServiceScopeFactory对象,我们依然和上面一样创建了一个自定义的Service,并将其命名为ServiceScopeFactoryService。与ServiceProviderService一样,ServiceScopeFactoryService同时也是一个ServiceCallSite,在Build和Invoke方法中它会返回一个ServiceScopeFactory对象。为了让这个它能够生效,我们依然在ServiceTable初始化的时自动添加一个相应的ServiceEntry。

   1: internal class ServiceScopeFactoryService : IService, IServiceCallSite

   2: {

   3:     public ServiceLifetime Lifetime=> ServiceLifetime.Scoped;

   4:     public IService Next { get; set; }

   5:  

   6:     public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)

   7:     {

   8:         return this;

   9:     }

  10:  

  11:     public Expression Build(Expression provider)

  12:     {

  13:         return Expression.New(typeof(ServiceScopeFactory).GetConstructors().Single(), provider);

  14:     }

  15:  

  16:     public object Invoke(ServiceProvider provider)

  17:     {

  18:         return new ServiceScopeFactory(provider);

  19:     }

  20: }

  21:  

  22: internal class ServiceTable

  23: {

  24:     public ServiceTable(IServiceCollection services)

  25:     {

  26:         //解析ServiceCollection并添加相应ServiceEntry

  27:         this.ServieEntries[typeof(IServiceProvider)] =  new ServiceEntry(new ServiceProviderService());

  28:         this.ServieEntries[typeof(IServiceScopeFactory)] = new ServiceEntry(new ServiceScopeFactoryService());

  29:     }

  30: }

三、提供一组服务的集合

到目前为止,我们自定义的ServiceProvider尚不具备原生ServiceProvider的一项特性,那就是当调用GetService方法时将服务类型指定为IEnumerable<T>或者直接调用扩展方法GetServices时,得到的是一个服务实例的集合。这个特性可以通过一个自定义的ServiceCallSite来完成,我们将其命名为EnumerableCallSite。

   1: internal class EnumerableCallSite : IServiceCallSite

   2: {

   3:     public Type ElementType { get; private set; }

   4:     public IServiceCallSite[] ServiceCallSites { get; private set; }

   5:  

   6:     public EnumerableCallSite(Type elementType, IServiceCallSite[] serviceCallSites)

   7:     {

   8:         this.ElementType = elementType;

   9:         this.ServiceCallSites = serviceCallSites;

  10:     }

  11:  

  12:     public Expression Build(Expression provider)

  13:     {

  14:         return Expression.NewArrayInit(this.ElementType, this.ServiceCallSites.Select(

  15:             it => Expression.Convert(it.Build(provider), this.ElementType)));

  16:     }

  17:  

  18:     public object Invoke(ServiceProvider provider)

  19:     {

  20:         var array = Array.CreateInstance(this.ElementType, this.ServiceCallSites.Length);

  21:         for (var index = 0; index < this.ServiceCallSites.Length; index++)

  22:         {

  23:             array.SetValue(this.ServiceCallSites[index].Invoke(provider), index);

  24:         }

  25:         return array;

  26:     }

  27: }

如上面的代码片段所示,EnumerableCallSite具有两个两个只读属性(ElementType和ServiceCallSites),前者表示返回的服务集合的元素类型,后者则返回一组用于提供集合元素的ServiceCallSite。在Invoke和Build方法中,我们只需要根据元素类型创建一个数组,并利用这组ServiceCallSite创建所有的元素即可。这个EnumerableCallSite最终按照如下的方式应用到ServiceProvider的GetServiceCallSite方法中。

   1: internal class ServiceProvider : IServiceProvider, IDisposable

   2: { 

   3:     public IServiceCallSite GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain)

   4:     {

   5:         try

   6:         {

   7:             if (callSiteChain.Contains(serviceType))

   8:             {

   9:                 throw new InvalidOperationException(string.Format("A circular dependency was detected for the service of type '{0}'",serviceType.FullName);

  10:             }

  11:             callSiteChain.Add(serviceType);

  12:             ServiceEntry serviceEntry;

  13:             if (this.ServiceTable.ServieEntries.TryGetValue(serviceType, out serviceEntry))

  14:             {

  15:                 return serviceEntry.Last.CreateCallSite(this, callSiteChain);

  16:             }

  17:  

  18:             if (serviceType.IsGenericType && serviceType.GetGenericTypeDefinition()== typeof(IEnumerable<>))

  19:             {

  20:                 Type elementType = serviceType.GetGenericArguments()[0];

  21:                 IServiceCallSite[] serviceCallSites = this.ServiceTable.ServieEntries.TryGetValue(elementType, out serviceEntry)

  22:                     ? serviceEntry.All.Select(it => it.CreateCallSite(this, callSiteChain)).ToArray()

  23:                     : new IServiceCallSite[0];

  24:                 return new EnumerableCallSite(elementType, serviceCallSites);

  25:             }

  26:  

  27:             return null;

  28:         }

  29:         finally

  30:         {

  31:             callSiteChain.Remove(serviceType);

  32:         }

  33:     }

  34:     //其他成员

  35: }

ASP.NET Core中的依赖注入(1):控制反转(IoC)
ASP.NET Core中的依赖注入(2):依赖注入(DI)
ASP.NET Core中的依赖注入(3):服务注册与提取
ASP.NET Core中的依赖注入(4):构造函数的选择与生命周期管理
ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【总体设计】
ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【解读ServiceCallSite】
ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【补充漏掉的细节】

ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【补充漏掉的细节】的更多相关文章

  1. ASP.NET Core中的依赖注入(1):控制反转(IoC)

    ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...

  2. ASP.NET Core中的依赖注入(2):依赖注入(DI)

    IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...

  3. ASP.NET Core中的依赖注入(3): 服务的注册与提供

    在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个可用的服务对象.ASP.NET Core ...

  4. ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理

    ServiceProvider最终提供的服务实例都是根据对应的ServiceDescriptor创建的,对于一个具体的ServiceDescriptor对象来说,如果它的ImplementationI ...

  5. ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【总体设计 】

    本系列前面的文章我们主要以编程的角度对ASP.NET Core的依赖注入系统进行了详细的介绍,如果读者朋友们对这些内容具有深刻的理解,我相信你们已经可以正确是使用这些与依赖注入相关的API了.如果你还 ...

  6. ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【解读ServiceCallSite 】

    通过上一篇的介绍我们应该对实现在ServiceProvider的总体设计有了一个大致的了解,但是我们刻意回避一个重要的话题,即服务实例最终究竟是采用何种方式提供出来的.ServiceProvider最 ...

  7. ASP.NET Core 中的依赖注入

    目录 什么是依赖注入 ASP .NET Core 中使用依赖注入 注册 使用 释放 替换为其它的 Ioc 容器 参考 什么是依赖注入 软件设计原则中有一个依赖倒置原则(DIP),为了更好的解耦,讲究要 ...

  8. ASP.NET Core 中的 依赖注入介绍

    ASP.NET Core 依赖注入 HomeController public class HomeController : Controller { private IStudentReposito ...

  9. ASP.NET Core 中的依赖注入 [共7篇]

    一.控制反转(IoC) ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了 ...

随机推荐

  1. POJ 1979 题解

    Red and Black Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 31722   Accepted: 17298 D ...

  2. IE11 上的3个bug

    1.IE 11在popstate上无法正常使用,所以,需要使用老方法hashchange.有一个叫History.js的library,是可以解决这个问题.但如果url在"#"后跟 ...

  3. WCF服务编程

    WCF服务编程, 我是WCF的初学者,在这想分享学习WCF服务编程的过程,欢迎大家多多指教!

  4. 使用js_md5加密密码

    为什么在传输过程中要用md5对密码进行加密? 众所周知,我们在表单中的输入框输入了密码后,如果采用ajax的post或者get方式提交数据,在浏览器的newwork中就可以看到我们向后台传输的内容,其 ...

  5. travis CI

    travis可对多语言持续继承,本文以nodejs 为例. 首先添加文件.travis.yml 中language: node_jsnode_js:  - "6"  - " ...

  6. Mac下搭建hexo

    Mac下搭建hexo 并部署到gitcafe 1.安装brewhome ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homeb ...

  7. Nodejs Promise的一点记录

    项目需要,看了点nodejs,其中比较难理解的就是Promise了,记录一下学习bluebird提供的Promise实现. Promise.promisifyAll(obj)方法 作用:把对象的方法属 ...

  8. PMP备考_第五章_项目范围管理_实践思考

    项目范围管理 前言 今天学习项目范围管理的内容,深切的感受到了原单位在项目管理方面存在的问题,今天在这里做一个总结,既相当于对项目范围的一个学习整理,也相当于自己对项目实践过程中存在问题的一个思考. ...

  9. java反射机制,通过类名获取对象,通过方法名和参数调

    import java.lang.reflect.Method;   import javax.persistence.Table; /**  * 通过注解javax.persistence.Tabl ...

  10. HTTP 错误 500.21 - Internal Server Error 处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”

    HTTP 错误 500.21 - Internal Server Error 处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipe ...