到目前為止,我們定義的ServiceProvider已經實現了基本的服務提供和回收功能,但是依然漏掉了一些必需的細節特性。這些特性包括如何針對IServiceProvider介面提供一個ServiceProvider對象,何創建ServiceScope,以及如何提供一個服務實例的集合。 一、提供一個... ...
到目前為止,我們定義的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: }