ASP.NET Core中的依赖注入,5:ServicePrvider实现揭秘【补充漏掉的细节】

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

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

class ServiceProviderService : IService, IServiceCallSite
   2: {
public ServiceLifetime Lifetime => ServiceLifetime.Scoped;
public IService Next { get; set; }
   5:  
public Expression Build(Expression provider)
   7:     {
return provider;
   9:     }
  10:  
public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
  12:     {
this;
  14:     }
  15:  
object Invoke(ServiceProvider provider)
  17:     {
return provider;
  19:     }
  20: }
  21:  
class ServiceTable
  23: {
public ServiceTable(IServiceCollection services)
  25:     {
//解析ServiceCollection并添加相应ServiceEntry
new ServiceProviderService());
  28:     }
  29: }



二、创建ServiceScope

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

class ServiceScope : IServiceScope
   2: {
private set; }
   4:  
public ServiceScope(ServiceProvider serviceProvider)
   6:     {
this.ServiceProvider = serviceProvider;
   8:     }
   9:  
void Dispose()
  11:     {
as IDisposable)?.Dispose();
  13:     }
  14: }
  15:  
class ServiceScopeFactory : IServiceScopeFactory
  17: {
private set; }
  19:  
public ServiceScopeFactory(ServiceProvider serviceProvider)
  21:     {
this.ServiceProvider = serviceProvider;
  23:     }
  24:  
public IServiceScope CreateScope()
  26:     {
this.ServiceProvider);
  28:     }
  29: }
  30:  
class ServiceProvider : IServiceProvider, IDisposable
  32: {
  33:     
public ServiceProvider(ServiceProvider parent)
  35:     {
this.Root = parent.Root;
this.ServiceTable = parent.ServiceTable;
  38:     }
  39: }

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

class ServiceScopeFactoryService : IService, IServiceCallSite
   2: {
public ServiceLifetime Lifetime=> ServiceLifetime.Scoped;
public IService Next { get; set; }
   5:  
public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
   7:     {
this;
   9:     }
  10:  
public Expression Build(Expression provider)
  12:     {
typeof(ServiceScopeFactory).GetConstructors().Single(), provider);
  14:     }
  15:  
object Invoke(ServiceProvider provider)
  17:     {
new ServiceScopeFactory(provider);
  19:     }
  20: }
  21:  
class ServiceTable
  23: {
public ServiceTable(IServiceCollection services)
  25:     {
//解析ServiceCollection并添加相应ServiceEntry
new ServiceProviderService());
new ServiceScopeFactoryService());
  29:     }
  30: }



三、提供一组服务的集合

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

class EnumerableCallSite : IServiceCallSite
   2: {
private set; }
private set; }
   5:  
public EnumerableCallSite(Type elementType, IServiceCallSite[] serviceCallSites)
   7:     {
this.ElementType = elementType;
this.ServiceCallSites = serviceCallSites;
  10:     }
  11:  
public Expression Build(Expression provider)
  13:     {
this.ServiceCallSites.Select(
this.ElementType)));
  16:     }
  17:  
object Invoke(ServiceProvider provider)
  19:     {
this.ServiceCallSites.Length);
this.ServiceCallSites.Length; index++)
  22:         {
this.ServiceCallSites[index].Invoke(provider), index);
  24:         }
return array;
  26:     }
  27: }

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

class ServiceProvider : IServiceProvider, IDisposable
   2: { 
public IServiceCallSite GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain)
   4:     {
try
   6:         {
if (callSiteChain.Contains(serviceType))
   8:             {
,serviceType.FullName);
  10:             }
  11:             callSiteChain.Add(serviceType);
  12:             ServiceEntry serviceEntry;
out serviceEntry))
  14:             {
this, callSiteChain);
  16:             }
  17:  
typeof(IEnumerable<>))
  19:             {
  20:                 Type elementType = serviceType.GetGenericArguments()[0];
out serviceEntry)
this, callSiteChain)).ToArray()
new IServiceCallSite[0];
new EnumerableCallSite(elementType, serviceCallSites);
  25:             }
  26:  
null;
  28:         }
finally
  30:         {
  31:             callSiteChain.Remove(serviceType);
  32:         }
  33:     }
//其他成员
  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实现揭秘【补充漏掉的细节】

www.weibo.com/artech

如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号)。

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

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

class ServiceProviderService : IService, IServiceCallSite
   2: {
public ServiceLifetime Lifetime => ServiceLifetime.Scoped;
public IService Next { get; set; }
   5:  
public Expression Build(Expression provider)
   7:     {
return provider;
   9:     }
  10:  
public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
  12:     {
this;
  14:     }
  15:  
object Invoke(ServiceProvider provider)
  17:     {
return provider;
  19:     }
  20: }
  21:  
class ServiceTable
  23: {
public ServiceTable(IServiceCollection services)
  25:     {
//解析ServiceCollection并添加相应ServiceEntry
new ServiceProviderService());
  28:     }
  29: }



二、创建ServiceScope

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

class ServiceScope : IServiceScope
   2: {
private set; }
   4:  
public ServiceScope(ServiceProvider serviceProvider)
   6:     {
this.ServiceProvider = serviceProvider;
   8:     }
   9:  
void Dispose()
  11:     {
as IDisposable)?.Dispose();
  13:     }
  14: }
  15:  
class ServiceScopeFactory : IServiceScopeFactory
  17: {
private set; }
  19:  
public ServiceScopeFactory(ServiceProvider serviceProvider)
  21:     {
this.ServiceProvider = serviceProvider;
  23:     }
  24:  
public IServiceScope CreateScope()
  26:     {
this.ServiceProvider);
  28:     }
  29: }
  30:  
class ServiceProvider : IServiceProvider, IDisposable
  32: {
  33:     
public ServiceProvider(ServiceProvider parent)
  35:     {
this.Root = parent.Root;
this.ServiceTable = parent.ServiceTable;
  38:     }
  39: }

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

class ServiceScopeFactoryService : IService, IServiceCallSite
   2: {
public ServiceLifetime Lifetime=> ServiceLifetime.Scoped;
public IService Next { get; set; }
   5:  
public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
   7:     {
this;
   9:     }
  10:  
public Expression Build(Expression provider)
  12:     {
typeof(ServiceScopeFactory).GetConstructors().Single(), provider);
  14:     }
  15:  
object Invoke(ServiceProvider provider)
  17:     {
new ServiceScopeFactory(provider);
  19:     }
  20: }
  21:  
class ServiceTable
  23: {
public ServiceTable(IServiceCollection services)
  25:     {
//解析ServiceCollection并添加相应ServiceEntry
new ServiceProviderService());
new ServiceScopeFactoryService());
  29:     }
  30: }



三、提供一组服务的集合

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

class EnumerableCallSite : IServiceCallSite
   2: {
private set; }
private set; }
   5:  
public EnumerableCallSite(Type elementType, IServiceCallSite[] serviceCallSites)
   7:     {
this.ElementType = elementType;
this.ServiceCallSites = serviceCallSites;
  10:     }
  11:  
public Expression Build(Expression provider)
  13:     {
this.ServiceCallSites.Select(
this.ElementType)));
  16:     }
  17:  
object Invoke(ServiceProvider provider)
  19:     {
this.ServiceCallSites.Length);
this.ServiceCallSites.Length; index++)
  22:         {
this.ServiceCallSites[index].Invoke(provider), index);
  24:         }
return array;
  26:     }
  27: }

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

class ServiceProvider : IServiceProvider, IDisposable
   2: { 
public IServiceCallSite GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain)
   4:     {
try
   6:         {
if (callSiteChain.Contains(serviceType))
   8:             {
,serviceType.FullName);
  10:             }
  11:             callSiteChain.Add(serviceType);
  12:             ServiceEntry serviceEntry;
out serviceEntry))
  14:             {
this, callSiteChain);
  16:             }
  17:  
typeof(IEnumerable<>))
  19:             {
  20:                 Type elementType = serviceType.GetGenericArguments()[0];
out serviceEntry)
this, callSiteChain)).ToArray()
new IServiceCallSite[0];
new EnumerableCallSite(elementType, serviceCallSites);
  25:             }
  26:  
null;
  28:         }
finally
  30:         {
  31:             callSiteChain.Remove(serviceType);
  32:         }
  33:     }
//其他成员
  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实现揭秘【补充漏掉的细节】