国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

香港云服务器
服務(wù)器之家 - 編程語言 - ASP.NET教程 - ASP.NET Core依賴注入系列教程之服務(wù)的注冊與提供

ASP.NET Core依賴注入系列教程之服務(wù)的注冊與提供

2020-06-03 15:00蔣金楠 ASP.NET教程

這篇文章主要給大家介紹了關(guān)于ASP.NET Core依賴注入系列教程之服務(wù)的注冊與提供的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧

前言

在采用了依賴注入的應(yīng)用中,我們總是直接利用DI容器直接獲取所需的服務(wù)實例,換句話說,DI容器起到了一個服務(wù)提供者的角色,它能夠根據(jù)我們提供的服務(wù)描述信息提供一個可用的服務(wù)對象。ASP.NET Core中的DI容器體現(xiàn)為一個實現(xiàn)了IServiceProvider接口的對象。

ServiceProvider與ServiceDescriptor
服務(wù)的注冊與提供
    利用ServiceProvider來提供服務(wù)
    提供一個服務(wù)實例的集合
    獲取ServiceProvider自身對象
    對泛型的支持

一、ServiceProvider與ServiceDescriptor

我一直覺得優(yōu)秀的設(shè)計首先應(yīng)該是簡單的設(shè)計,至少是看起來簡單的設(shè)計,這就是我們所謂的大道至簡。作為一個服務(wù)的提供者,ASP.NET Core中的DI容器最終體現(xiàn)為一個IServiceProvider接口,我們將所有實現(xiàn)了該接口的類型及其實例統(tǒng)稱為ServiceProvider。如下面的代碼片段所示,該接口簡單至極,它僅僅提供了唯一個GetService方法,該方法根據(jù)提供的服務(wù)類型為你提供對應(yīng)的服務(wù)實例。

?
1
2
3
4
public interface IServiceProvider
{
object GetService(Type serviceType);
}

ASP.NET Core內(nèi)部真正使用的是一個實現(xiàn)了IServiceProvider接口的內(nèi)部類型(該類型的名稱為“ServiceProvider”),我們不能直接創(chuàng)建該對象,只能間接地通過調(diào)用IServiceCollection接口的擴展方法BuildServiceProvider得到它。IServiceCollection接口定義在“Microsoft.Extensions.DependencyInjection”命名空間下,如果沒有特別說明,本系列文章涉及到的與ASP.NET Core依賴注入相關(guān)的類型均采用此命名空間。 如下面的代碼片段所示,IServiceCollection接口實際上代表一個元素為ServiceDescriptor對象的集合,它直接繼承了另一個接口IList<ServiceDescriptor>,而ServiceCollection類實現(xiàn)了該接口。

?
1
2
3
4
5
6
7
8
9
10
11
12
public static class ServiceCollectionExtensions
{
public static IServiceProvider BuildServiceProvider(this IServiceCollection services);
}
 
public interface IServiceCollection : IList<ServiceDescriptor>
{}
 
Public class ServiceCollection: IServiceCollection
{
//省略成員
}

體現(xiàn)為DI容器的ServiceProvider之所以能夠根據(jù)我們給定的服務(wù)類型(一般是一個接口類型)提供一個能夠開箱即用的服務(wù)實例,是因為我們預(yù)先注冊了相應(yīng)的服務(wù)描述信息,這些指導(dǎo)ServiceProvider正確實施服務(wù)提供操作的服務(wù)描述體現(xiàn)為如下一個ServiceDescriptor類型。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ServiceDescriptor
{
public ServiceDescriptor(Type serviceType, object instance);
public ServiceDescriptor(Type serviceType, Func<IServiceProvider, object> factory, ServiceLifetime lifetime);
public ServiceDescriptor(Type serviceType, Type implementationType, ServiceLifetime lifetime);
 
public Type ServiceType { get; }
public ServiceLifetime Lifetime { get; }
 
public Type ImplementationType { get; }
public object ImplementationInstance { get; }
public Func<IServiceProvider, object> ImplementationFactory { get; }
}

ServiceDescriptor的ServiceType屬性代表提供服務(wù)的生命類型,由于標(biāo)準(zhǔn)化的服務(wù)一般會定義成接口,所以在絕大部分情況下體現(xiàn)為一個接口類型。類型為ServiceLifetime的屬性Lifetime體現(xiàn)了ServiceProvider針對服務(wù)實例生命周期的控制方式。如下面的代碼片段所示,ServiceLifetime是一個美劇類型,定義其中的三個選項(Singleton、Scoped和Transient)體現(xiàn)三種對服務(wù)對象生命周期的控制形式,我們將在本節(jié)后續(xù)部分對此作專門的介紹。

?
1
2
3
4
5
6
public enum ServiceLifetime
{
Singleton,
Scoped,
Transient
}

3-10對于ServiceDescriptor的其他三個屬性來說,它們實際上是輔助ServiceProvider完成具體的服務(wù)實例提供操。ImplementationType屬性代表被提供服務(wù)實例的真實類型,屬性ImplementationInstance則直接代表被提供的服務(wù)實例,ImplementationFactory則提供了一個創(chuàng)建服務(wù)實例的委托對象。ASP.NET Core與依賴注入相關(guān)的幾個核心類型具有如圖10所示的關(guān)系。

由于ASP.NET Core中的ServiceProvider是根據(jù)一個代表ServiceDescriptor集合的IServiceCollection對象創(chuàng)建的,當(dāng)我們調(diào)用其GetService方法的時候,它會根據(jù)我們提供的服務(wù)類型找到對應(yīng)的ServiceDecriptor對象。如果該ServiceDecriptor對象的ImplementationInstance屬性返回一個具體的對象,該對象將直接用作被提供的服務(wù)實例。如果ServiceDecriptor對象的ImplementationFactory返回一個具體的委托,該委托對象將直接用作創(chuàng)建服務(wù)實例的工廠。

如果這兩個屬性均為Null,ServiceProvider才會根據(jù)ImplementationType屬性返回的類型調(diào)用相應(yīng)的構(gòu)造函數(shù)創(chuàng)建被提供的服務(wù)實例。至于我們在上面一節(jié)中提到的三種依賴注入方式,ServiceProvider僅僅支持構(gòu)造器注入,屬性注入和方法注入的支持并未提供。

二、服務(wù)的注冊與提供

ASP.NET Core針對依賴注入的編程主要體現(xiàn)在兩個方面:其一,創(chuàng)建一個ServiceCollection對象并將服務(wù)注冊信息以ServiceDescriptor對象的形式添加其中;其二,針對ServiceCollection對象創(chuàng)建對應(yīng)的ServiceProvider并利用它提供我們需要的服務(wù)實例。

在進行服務(wù)注冊的時候,我們可以直接調(diào)用相應(yīng)的構(gòu)造函數(shù)創(chuàng)建ServiceDescriptor對象并將其添加到ServiceCollection對象之中。除此之外,IServiceCollection接口還具有如下三組擴展方法將這兩個步驟合二為一。從下面給出的代碼片段我們不難看出這三組擴展方法分別針對上面我們提及的三種針對服務(wù)實例的生命周期控制方式,泛型參數(shù)TService代表服務(wù)的聲明類型,即ServiceDescriptor的ServiceType屬性,至于ServiceDescriptor的其他屬性,則通過方法相應(yīng)的參數(shù)來提供。

?
1
2
3
4
5
6
7
8
9
10
11
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddScoped<TService>(this IServiceCollection services) where TService: class;
//其他AddScoped<TService>重載
 
public static IServiceCollection AddSingleton<TService>(this IServiceCollection services) where TService: class;
//其他AddSingleton<TService>重載
 
public static IServiceCollection AddTransient<TService>(this IServiceCollection services) where TService: class;
//其他AddTransient<TService>重載
}

對于用作DI容器的ServiceProvider對象來說,我們可以直接調(diào)用它的GetService方法根據(jù)指定的服務(wù)類型獲得想用的服務(wù)實例。除此之外,服務(wù)的提供還可以通過IServiceProvider接口相應(yīng)的擴展方法來完成。如下面的代碼片段所示,擴展方法GetService<T>以泛型參數(shù)的形式指定服務(wù)的聲明類型。至于另外兩個擴展方法GetRequiredService和GetRequiredService<T>,如果ServiceProvider不能提供一個具體的服務(wù)實例,一個InvalidOperationException異常會被拋出來并提示相應(yīng)的服務(wù)注冊信息不足。

?
1
2
3
4
5
6
public static class ServiceProviderExtensions
{
public static T GetService<T>(this IServiceProvider provider);
public static object GetRequiredService(this IServiceProvider provider, Type serviceType);
public static T GetRequiredService<T>(this IServiceProvider provider);
}

利用ServiceProvider來提供服務(wù)

接下來采用實例演示的方式來介紹如何利用ServiceCollection進行服務(wù)注冊,以及如何利用ServiceCollection創(chuàng)建對應(yīng)的ServiceProvider來提供我們需要的服務(wù)實例。我們創(chuàng)建一個ASP.NET Core控制臺程序,并在project.json中按照如下的方式添加針對 “Microsoft.Extensions.DepedencyInjection”這個NuGet包的依賴。

?
1
2
3
4
5
6
{
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "1.0.0-rc1-final"
},
...
}

我們接下來定義四個服務(wù)接口(IFoo、IBar、IBaz和IGux)以及分別實現(xiàn)它們的四個服務(wù)類(Foo、Bar、Baz和Gux)如下面的代碼片段所示,IGux具有三個只讀屬性(Foo、Bar和Baz)均為接口類型,并在構(gòu)造函數(shù)中進行初始化。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public interface IFoo {}
public interface IBar {}
public interface IBaz {}
public interface IGux
{
IFoo Foo { get; }
IBar Bar { get; }
IBaz Baz { get; }
}
 
public class Foo : IFoo {}
public class Bar : IBar {}
public class Baz : IBaz {}
public class Gux : IGux
{
public IFoo Foo { get; private set; }
public IBar Bar { get; private set; }
public IBaz Baz { get; private set; }
 
public Gux(IFoo foo, IBar bar, IBaz baz)
{
this.Foo = foo;
this.Bar = bar;
this.Baz = baz;
}
}

現(xiàn)在我們在作為程序入口的Main方法中創(chuàng)建了一個ServiceCollection對象,并采用不同的方式完成了針對四個服務(wù)接口的注冊。具體來說,對于正對服務(wù)接口IFoo和IGux的ServiceDescriptor來說,我們指定了代表服務(wù)真實類型的ImplementationType屬性,而對于針對服務(wù)接口IBar和IBaz的ServiceDescriptor來說,我們初始化的則是分別代表服務(wù)實例和服務(wù)工廠的ImplementationInstance個ImplementationFactory屬性。由于我們調(diào)用的是AddSingleton方法,所以四個ServiceDescriptor的Lifetime屬性均為Singleton。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Program
{
static void Main(string[] args)
{
IServiceCollection services = new ServiceCollection()
.AddSingleton<IFoo, Foo>()
.AddSingleton<IBar>(new Bar())
.AddSingleton<IBaz>(_ => new Baz())
.AddSingleton<IGux, Gux>();
 
IServiceProvider serviceProvider = services.BuildServiceProvider();
Console.WriteLine("serviceProvider.GetService<IFoo>(): {0}",serviceProvider.GetService<IFoo>());
Console.WriteLine("serviceProvider.GetService<IBar>(): {0}", serviceProvider.GetService<IBar>());
Console.WriteLine("serviceProvider.GetService<IBaz>(): {0}", serviceProvider.GetService<IBaz>());
Console.WriteLine("serviceProvider.GetService<IGux>(): {0}", serviceProvider.GetService<IGux>());
}
}

接下來我們調(diào)用ServiceCollection對象的擴展方法BuildServiceProvider得到對應(yīng)的ServiceProvider對象,然后調(diào)用其擴展方法GetService<T>分別獲得針對四個接口的服務(wù)實例對象并將類型名稱其輸出到控制臺上。運行該程序之后,我們會在控制臺上得到如下的輸出結(jié)果,由此印證ServiceProvider為我們提供了我們期望的服務(wù)實例。

?
1
2
3
4
serviceProvider.GetService<IFoo>(): Foo
serviceProvider.GetService<IBar>(): Bar
serviceProvider.GetService<IBaz>(): Baz
serviceProvider.GetService<IGux>(): Gux

提供一個服務(wù)實例的集合

如果我們在調(diào)用GetService方法的時候?qū)⒎?wù)類型指定為IEnumerable<T>,那么返回的結(jié)果將會是一個集合對象。除此之外, 我們可以直接調(diào)用IServiceProvider如下兩個擴展方法GetServeces達到相同的目的。在這種情況下,ServiceProvider將會利用所有與指定服務(wù)類型相匹配的ServiceDescriptor來提供具體的服務(wù)實例,這些均會作為返回的集合對象的元素。如果所有的ServiceDescriptor均與指定的服務(wù)類型不匹配,那么最終返回的是一個空的集合對象。

?
1
2
3
4
5
public static class ServiceProviderExtensions
{
public static IEnumerable<T> GetServices<T>(this IServiceProvider provider);
public static IEnumerable<object> GetServices(this IServiceProvider provider, Type serviceType);
}

值得一提的是,如果ServiceProvider所在的ServiceCollection包含多個具有相同服務(wù)類型(對應(yīng)ServiceType屬性)的ServiceDescriptor,當(dāng)我們調(diào)用GetService方法獲取單個服務(wù)實例的時候,只有最后一個ServiceDescriptor才是有效的,至于其他的ServiceDescriptor,它們只有在獲取服務(wù)集合的場景下才有意義。

我們通過一個簡單的實例來演示如何利用ServiceProvider得到一個包含多個服務(wù)實例的集合。我們在一個控制臺應(yīng)用中定義了如下一個服務(wù)接口IFoobar,兩個服務(wù)類型Foo和Bar均實現(xiàn)了這個接口。在作為程序入口的Main方法中,我們將針針對服務(wù)類型Foo和Bar的兩個ServiceDescriptor添加到創(chuàng)建的ServiceCollection對象中,這兩個ServiceDescriptor對象的ServiceType屬性均為IFoobar。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Program
{
static void Main(string[] args)
{
 IServiceCollection serviceCollection = new ServiceCollection()
 .AddSingleton<IFoobar, Foo>()
 .AddSingleton<IFoobar, Bar>();
 
 IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
 Console.WriteLine("serviceProvider.GetService<IFoobar>(): {0}", serviceProvider.GetService<IFoobar>());
 
 IEnumerable<IFoobar> services = serviceProvider.GetServices<IFoobar>();
 int index = 1;
 Console.WriteLine("serviceProvider.GetServices<IFoobar>():");
 foreach (IFoobar foobar in services)
 {
 Console.WriteLine("{0}: {1}", index++, foobar);
 }
}
}
 
public interface IFoobar {}
public class Foo : IFoobar {}
public class Bar : IFoobar {}

在調(diào)用ServiceCollection對象的擴展方法BuildServiceProvider得到對應(yīng)的ServiceProvider對象之后,我們先調(diào)用其GetService<T>方法以確定針對服務(wù)接口IFoobar得到的服務(wù)實例的真實類型就是是Foo還是Bar。接下來我們調(diào)用ServiceProvider的擴展方法GetServices<T>獲取一組針對服務(wù)接口IFoobar的服務(wù)實例并將它們的真是類型打印在控制臺上。該程序運行后將會在控制臺上生成如下的輸出結(jié)果。

?
1
2
3
4
serviceProvider.GetService<IFoobar>(): Bar
serviceProvider.GetServices<IFoobar>():
1: Foo
2: Bar

獲取ServiceProvider自身對象

對于ServiceProvider的服務(wù)提供機制來說,還有一個小小的細節(jié)值得我們關(guān)注,那就是當(dāng)我們調(diào)用GetService或者GetRequiredService方法的時候若將服務(wù)類型設(shè)定為IServiceProvider,那么得到的對象實際上就是ServiceProvider自身這個對象。與之同理,調(diào)用GetServices方法將會返回一個包含自身的集合。如下所示的代碼片段體現(xiàn)了ServiceProvider的這個特性。

?
1
2
3
4
5
6
7
8
9
class Program
{
 static void Main(string[] args)
 {
  IServiceProvider serviceProvider = new ServiceCollection().BuildServiceProvider();
  Debug.Assert(object.ReferenceEquals(serviceProvider, serviceProvider.GetService<IServiceProvider>()));
  Debug.Assert(object.ReferenceEquals(serviceProvider, serviceProvider.GetServices<IServiceProvider>().Single()));
 }
}

對泛型的支持

ServiceProvider提供的服務(wù)實例不僅限于普通的類型,它對泛型服務(wù)類型同樣支持。在針對泛型服務(wù)進行注冊的時候,我們可以將服務(wù)類型設(shè)定為攜帶具體泛型參數(shù)的“關(guān)閉泛型類型”(比如IFoobar<IFoo,IBar>),除此之外服務(wù)類型也可以是包含具體泛型參數(shù)的“開放泛型類型”(比如IFoo<,>)。前者實際上還是將其視為非泛型服務(wù)來對待,后者才真正體現(xiàn)了“泛型”的本質(zhì)。

比如我們注冊了某個泛型服務(wù)接口IFoobar<,>與它的實現(xiàn)類Foobar<,>之間的映射關(guān)系,當(dāng)我們指定一個攜帶具體泛型參數(shù)的服務(wù)接口類型IFoobar<IFoo,IBar>并調(diào)用ServiceProvider的GetService方法獲取對應(yīng)的服務(wù)實例時,ServiceProvider會針對指定的泛型參數(shù)類型(IFoo和IBar)來解析與之匹配的實現(xiàn)類型(可能是Foo和Baz)并得到最終的實現(xiàn)類型(Foobar<Foo,Baz>)。

我們同樣利用一個簡單的控制臺應(yīng)用來演示基于泛型的服務(wù)注冊與提供方式。如下面的代碼片段所示,我們定義了三個服務(wù)接口(IFoo、IBar和IFoobar<T1,T2>)和實現(xiàn)它們的三個服務(wù)類(Foo、Bar個Foobar<T1,T2>),泛型接口具有兩個泛型參數(shù)類型的屬性(Foo和Bar),它們在實現(xiàn)類中以構(gòu)造器注入的方式被初始化。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Program
{
 static void Main(string[] args)
 {
  IServiceProvider serviceProvider = new ServiceCollection()
   .AddTransient<IFoo, Foo>()
   .AddTransient<IBar, Bar>()
   .AddTransient(typeof(IFoobar<,>), typeof(Foobar<,>))
   .BuildServiceProvider();
 
  Console.WriteLine("serviceProvider.GetService<IFoobar<IFoo, IBar>>().Foo: {0}", serviceProvider.GetService<IFoobar<IFoo, IBar>>().Foo);
12:   Console.WriteLine("serviceProvider.GetService<IFoobar<IFoo, IBar>>().Bar: {0}", serviceProvider.GetService<IFoobar<IFoo, IBar>>().Bar);
 }
}
 
public interface IFoobar<T1, T2>
{
 T1 Foo { get; }
 T2 Bar { get; }
}
public interface IFoo {}
public interface IBar {}
 
public class Foobar<T1, T2> : IFoobar<T1, T2>
{
 public T1 Foo { get; private set; }
 public T2 Bar { get; private set; }
 public Foobar(T1 foo, T2 bar)
 {
  this.Foo = foo;
  this.Bar = bar;
 }
}
public class Foo : IFoo {}
public class Bar : IBar {}

在作為入口程序的Main方法中,我們創(chuàng)建了一個ServiceCollection對象并采用Transient模式注冊了上述三個服務(wù)接口與對應(yīng)實現(xiàn)類型之間的映射關(guān)系,對于泛型服務(wù)IFoobar<T1,T2>/Foobar<T1,T2>來說,我們指定的是不攜帶具體泛型參數(shù)的開放泛型類型IFoobar<,>/Foobar<,>。利用此ServiceCollection創(chuàng)建出對應(yīng)的ServiceProvider之后,我們調(diào)用后者的GetService方法并指定IFoobar<IFoo,IBar>為服務(wù)類型。得到的服務(wù)對象將會是一個Foobar<Foo,Bar>對象,我們將它的Foo和Bar屬性類型輸出于控制臺上作為驗證。該程序執(zhí)行之后將會在控制臺上產(chǎn)生下所示的輸出結(jié)果。

?
1
2
serviceProvider.GetService<IFoobar<IFoo, IBar>>().Foo: Foo
serviceProvider.GetService<IFoobar<IFoo, IBar>>().Bar: Bar

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。

原文鏈接:http://www.cnblogs.com/artech/p/asp-net-core-di-register.html

延伸 · 閱讀

精彩推薦
491
主站蜘蛛池模板: 成人免费黄色片 | 一区二区在线视频 | 北条麻妃一区二区三区中文字幕 | 亚洲综合一区二区 | 在线视频亚洲 | 欧美日韩国产高清 | 精品欧美一区二区三区久久久 | 综合网激情| 一本大道久久精品 | 影音先锋在线看片资源 | 欧美自拍小视频 | 国产精品正在播放 | 91精品中文字幕一区二区三区 | 蜜桃视频一区二区 | 黄色网免费看 | 美女视频一区 | 一级毛片免费完整视频 | 欧美日韩中文字幕 | 91精品国产91久久久久久 | 噜噜噜噜狠狠狠7777视频 | 国产免费一区二区 | 欧美日韩在线免费 | 中文字幕中文字幕 | 国产精品久久久久无码av | 日韩在线精品视频 | 日韩美女在线 | 精品久久久久久亚洲综合网 | 国产高清在线a视频大全 | 中文字幕一区二区三区在线观看 | 北条麻妃在线一区二区免费播放 | 99久久99久久精品 | 国产欧美精品区一区二区三区 | 国产一区色 | 久久久久国产精品免费 | 性色视频免费观看 | 久久中文字幕av | 激情久久av一区av二区av三区 | 欧美日韩在线播放 | 亚洲欧美在线精品 | 中文字幕在线观看不卡视频 | 欧美日韩精品电影 |