ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【补充漏掉的细节】
2016-04-16 23:21
936 查看
到目前为止,我们定义的ServiceProvider已经实现了基本的服务提供和回收功能,但是依然漏掉了一些必需的细节特性。这些特性包括如何针对IServiceProvider接口提供一个ServiceProvider对象,何创建ServiceScope,以及如何提供一个服务实例的集合。
创建ServiceScope的目的在于创建作为当前ServiceProvider儿子的另一个ServiceProvider,新创建的ServiceProvider不仅与原来的ServiceProvider具有相同的根,同时共享所有的服务注册信息。利用这个新的ServiceProvider来代替现有的ServiceProvider,其主要的目的还是使我们能够及时地回收提供的服务实例。ServiceScope是通过它的工厂ServiceScopeFactory来创建的,所以先创建了如下一个ServiceScopeFactory类和对应的ServiceScope,它们的定义与我们在前面一节介绍的完全一致。
为了让ServiceProvider的GetService方法在服务类型指定为IServiceScopeFactory接口的时候能够自动返回上面我们定义的ServiceScopeFactory对象,我们依然和上面一样创建了一个自定义的Service,并将其命名为ServiceScopeFactoryService。与ServiceProviderService一样,ServiceScopeFactoryService同时也是一个ServiceCallSite,在Build和Invoke方法中它会返回一个ServiceScopeFactory对象。为了让这个它能够生效,我们依然在ServiceTable初始化的时自动添加一个相应的ServiceEntry。
到目前为止,我们自定义的ServiceProvider尚不具备原生ServiceProvider的一项特性,那就是当调用GetService方法时将服务类型指定为IEnumerable<T>或者直接调用扩展方法GetServices时,得到的是一个服务实例的集合。这个特性可以通过一个自定义的ServiceCallSite来完成,我们将其命名为EnumerableCallSite。
如上面的代码片段所示,EnumerableCallSite具有两个两个只读属性(ElementType和ServiceCallSites),前者表示返回的服务集合的元素类型,后者则返回一组用于提供集合元素的ServiceCallSite。在Invoke和Build方法中,我们只需要根据元素类型创建一个数组,并利用这组ServiceCallSite创建所有的元素即可。这个EnumerableCallSite最终按照如下的方式应用到ServiceProvider的GetServiceCallSite方法中。
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实现揭秘【补充漏掉的细节】
一、提供一个ServiceProvider对象
我们知道当将服务类型指定为IServiceProvider接口并调用ServiceProvider的GetService方法是,ServiceProvider对象本身将会作为服务实例返回,这个特性可以利用一个自定义的Service来实现。如下面的代码片段所示,我们定义的这个ServiceProviderService既是一个Service,又是一个ServiceCallSite。它默认采用生命周期管理模式为Scoped,在Invoke和Build方法中,它直接将当前ServiceProvider作为提供的服务实例。在初始化ServiceTable的时候,我们额外添加一个针对ServiceProviderService的ServideEntry。internal class ServiceProviderService : IService, IServiceCallSite
{
public ServiceLifetime Lifetime => ServiceLifetime.Scoped;
public IService Next{ get; set;}
public Expression Build(Expression provider)
{
return provider;
}
public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
{
return this;
}
public object Invoke(ServiceProvider provider)
{
return provider;
}
}
internal class ServiceTable
{
public ServiceTable(IServiceCollection services)
{
//解析ServiceCollection并添加相应ServiceEntry
this.ServieEntries[typeof(IServiceProvider)] = new ServiceEntry(new ServiceProviderService());
}
}
二、创建ServiceScope
创建ServiceScope的目的在于创建作为当前ServiceProvider儿子的另一个ServiceProvider,新创建的ServiceProvider不仅与原来的ServiceProvider具有相同的根,同时共享所有的服务注册信息。利用这个新的ServiceProvider来代替现有的ServiceProvider,其主要的目的还是使我们能够及时地回收提供的服务实例。ServiceScope是通过它的工厂ServiceScopeFactory来创建的,所以先创建了如下一个ServiceScopeFactory类和对应的ServiceScope,它们的定义与我们在前面一节介绍的完全一致。internal class ServiceScope : IServiceScope
{
public IServiceProvider ServiceProvider{ get; private set;}
public ServiceScope(ServiceProvider serviceProvider)
{
this.ServiceProvider = serviceProvider;
}
public void Dispose()
{
(this.ServiceProvider as IDisposable)?.Dispose();
}
}
internal class ServiceScopeFactory : IServiceScopeFactory
{
public ServiceProvider ServiceProvider{ get; private set;}
public ServiceScopeFactory(ServiceProvider serviceProvider)
{
this.ServiceProvider = serviceProvider;
}
public IServiceScope CreateScope()
{
return new ServiceScope(this.ServiceProvider);
}
}
internal class ServiceProvider : IServiceProvider, IDisposable
{
public ServiceProvider(ServiceProvider parent)
{
this.Root = parent.Root;
this.ServiceTable = parent.ServiceTable;
}
}
为了让ServiceProvider的GetService方法在服务类型指定为IServiceScopeFactory接口的时候能够自动返回上面我们定义的ServiceScopeFactory对象,我们依然和上面一样创建了一个自定义的Service,并将其命名为ServiceScopeFactoryService。与ServiceProviderService一样,ServiceScopeFactoryService同时也是一个ServiceCallSite,在Build和Invoke方法中它会返回一个ServiceScopeFactory对象。为了让这个它能够生效,我们依然在ServiceTable初始化的时自动添加一个相应的ServiceEntry。
internal class ServiceScopeFactoryService : IService, IServiceCallSite
{
public ServiceLifetime Lifetime=> ServiceLifetime.Scoped;
public IService Next{ get; set;}
public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
{
return this;
}
public Expression Build(Expression provider)
{
return Expression.New(typeof(ServiceScopeFactory).GetConstructors().Single(), provider);
}
public object Invoke(ServiceProvider provider)
{
return new ServiceScopeFactory(provider);
}
}
internal class ServiceTable
{
public ServiceTable(IServiceCollection services)
{
//解析ServiceCollection并添加相应ServiceEntry
this.ServieEntries[typeof(IServiceProvider)] =new ServiceEntry(new ServiceProviderService());
this.ServieEntries[typeof(IServiceScopeFactory)] = new ServiceEntry(new ServiceScopeFactoryService());
}
}
三、提供一组服务的集合
到目前为止,我们自定义的ServiceProvider尚不具备原生ServiceProvider的一项特性,那就是当调用GetService方法时将服务类型指定为IEnumerable<T>或者直接调用扩展方法GetServices时,得到的是一个服务实例的集合。这个特性可以通过一个自定义的ServiceCallSite来完成,我们将其命名为EnumerableCallSite。internal class EnumerableCallSite : IServiceCallSite
{
public Type ElementType{ get; private set;}
public IServiceCallSite[] ServiceCallSites{ get; private set;}
public EnumerableCallSite(Type elementType, IServiceCallSite[] serviceCallSites)
{
this.ElementType = elementType;
this.ServiceCallSites = serviceCallSites;
}
public Expression Build(Expression provider)
{
return Expression.NewArrayInit(this.ElementType, this.ServiceCallSites.Select(
it => Expression.Convert(it.Build(provider), this.ElementType)));
}
public object Invoke(ServiceProvider provider)
{
var array = Array.CreateInstance(this.ElementType, this.ServiceCallSites.Length);
for (var index = 0; index < this.ServiceCallSites.Length; index++)
{
array.SetValue(this.ServiceCallSites[index].Invoke(provider), index);
}
return array;
}
}
如上面的代码片段所示,EnumerableCallSite具有两个两个只读属性(ElementType和ServiceCallSites),前者表示返回的服务集合的元素类型,后者则返回一组用于提供集合元素的ServiceCallSite。在Invoke和Build方法中,我们只需要根据元素类型创建一个数组,并利用这组ServiceCallSite创建所有的元素即可。这个EnumerableCallSite最终按照如下的方式应用到ServiceProvider的GetServiceCallSite方法中。
internal class ServiceProvider : IServiceProvider, IDisposable
{
public IServiceCallSite GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain)
{
try
{
if (callSiteChain.Contains(serviceType))
{
throw new InvalidOperationException(string.Format("A circular dependency was detected for the service of type '{0}'",serviceType.FullName);
}
callSiteChain.Add(serviceType);
ServiceEntry serviceEntry;
if (this.ServiceTable.ServieEntries.TryGetValue(serviceType, out serviceEntry))
{
return serviceEntry.Last.CreateCallSite(this, callSiteChain);
}
if (serviceType.IsGenericType && serviceType.GetGenericTypeDefinition()== typeof(IEnumerable<>))
{
Type elementType = serviceType.GetGenericArguments()[0];
IServiceCallSite[] serviceCallSites = this.ServiceTable.ServieEntries.TryGetValue(elementType, out serviceEntry)
? serviceEntry.All.Select(it => it.CreateCallSite(this, callSiteChain)).ToArray()
: new IServiceCallSite[0];
return new EnumerableCallSite(elementType, serviceCallSites);
}
return null;
}
finally
{
callSiteChain.Remove(serviceType);
}
}
//其他成员
}
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 Forms身份验证详解
- asp.net mvc +easyui 实现权限管理(二)
- asp.net网站的初探
- asp.net中页面按钮回车默认执行 设置方法
- asp.net webapi 参数绑定总结
- 使用一般处理程序,模拟ASP.NET MVC,开发一个轻量级的学习版MVC框架。
- 网站后台登录aspcms 提示错误号:-2147467259,错误描述:操作必须使用一个可更新的查询。sql=update AspCms_Content set TimeStatus=0 where TimeStatus=1 and Timeing <= 解决方法。
- ASP.NET MVC 基础(01)
- RaspberryPi2 安装系统到硬盘
- asp 用 PagedDataSource 为 datalist 添加分页需注意
- ASP+JS三级联动下拉菜单
- ASP.NET 页面缓存
- ASP.NET Core 1.0
- 中文VS2008 安装ASP.NET MVC框架问题?
- 中文VS2008 安装ASP.NET MVC框架问题?
- ASP.NET MVC之如何看待内置配置来提高性能优化(四)
- Asp.net 服务器控件
- ASP.NET中使用DataGrid控件按照条件显示GridView单元格的颜色
- 浅谈ASP.NET报表控件
- jasperreport position type 详解