日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

探索 .NET Core 依赖注入的 IServiceCollection

發(fā)布時(shí)間:2023/12/4 asp.net 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 探索 .NET Core 依赖注入的 IServiceCollection 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

如果您使用了.NET Core,則很可能已使用Microsoft.Extensions.DependencyInjection中的內(nèi)置依賴項(xiàng)注入容器,在本文中,我想更深入地了解Microsoft Dependency Injection(DI)容器中的 IServiceCollection。

什么是依賴注入(DI)和DI容器?

Microsoft依賴項(xiàng)注入容器只是一組類,它們組合到一個(gè)代碼庫(kù)中,這個(gè)庫(kù)會(huì)自動(dòng)創(chuàng)建并管理程序中需要的對(duì)象。

我們先看下面的代碼:

public class ClassA {public void DoWork() {var b = new ClassB();b.DoStuff();} }public class ClassB {public void DoStuff(){// ...} }

ClassA直接依賴ClassB,并且在它的DoWork方法中,new了一個(gè)ClassB,然后調(diào)用了ClassB的DoStuff方法。

我們改寫一下代碼看看:

public class ClassA {private readonly ClassB _dependency;public ClassA(ClassB classB) => _dependency = classB;public void DoWork() => _dependency.DoStuff(); }public class ClassB : IThing {public void DoStuff(){// ...} }

首先,我加了一個(gè)構(gòu)造函數(shù),并且指定了ClassA依賴的類型,調(diào)用構(gòu)造函數(shù)時(shí),必須提供ClassB的實(shí)例, 在ClassA的內(nèi)部,我們不會(huì)去new一個(gè)ClassB,ClassB完全是由外部傳入的,這里就是控制反轉(zhuǎn)(IoC)。

進(jìn)一步改進(jìn)代碼:

public interface IThing {public void DoStuff(); }public class ClassA {private readonly IThing _dependency;public ClassA(IThing thing) => _dependency = thing;public void DoWork() => _dependency.DoStuff(); }public class ClassB : IThing {public void DoStuff(){// ...} }

加了一個(gè)接口IThing,現(xiàn)在,我們已經(jīng)應(yīng)用了SOLID的依賴倒置原則,我們不再依賴具體的實(shí)現(xiàn),相反,我們依賴于IThing抽象,在構(gòu)造函數(shù)中,只需要傳入IThing的實(shí)現(xiàn)就好了。

然后在我們的代碼中,可以這樣用:

class Program {static void Main(string[] args){IThing thing = new ClassB();ClassA classA = new ClassA(thing);classA.DoWork();} }

我們手動(dòng)new了一個(gè)ClassB,它實(shí)現(xiàn)了IThing接口,然后創(chuàng)建ClassA的時(shí)候,直接把thing傳入構(gòu)造函數(shù)中。

上面的代碼演示,我們只處理了ClassA和ClassB的依賴注入關(guān)系,但是在實(shí)際中呢,我們代碼中有很多類型,然后有各種各樣的依賴關(guān)系。

這個(gè)時(shí)候我們就需要一個(gè)DI容器,我們對(duì)容器進(jìn)行配置,然它知道什么類型,然后負(fù)責(zé)自動(dòng)創(chuàng)建并管理對(duì)象(通常稱為服務(wù))。

注冊(cè)服務(wù)

通常, Microsoft DI 容器需要在Startup類中配置,在這里,您可以使用ConfigureServices方法向容器注冊(cè)服務(wù),在應(yīng)用程序托管生命周期的早期,將調(diào)用ConfigureServices方法,它有一個(gè)參數(shù)IServiceCollection,這個(gè)參數(shù)在初始化應(yīng)用程序時(shí)傳入。

public class Startup {public void ConfigureServices(IServiceCollection services){// 注冊(cè)服務(wù)}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){} }

為了盡可能的簡(jiǎn)單,我們也可以在控制臺(tái)中使用 Microsoft DependencyInjection。

創(chuàng)建控制臺(tái)程序后,我們首先在項(xiàng)目中引入Microsoft.Extensions.DependencyInjection

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net5.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" /></ItemGroup></Project>

現(xiàn)在我們開始注冊(cè)我們的服務(wù),但是我們需要一個(gè)IServiceCollection,讓我們看一下IServiceCollection的定義。

public interface IServiceCollection : IList<ServiceDescriptor> { }

IServiceCollection沒有定義其任何成員,而是從IList<ServiceDescriptor>派生。

在Microsoft.Extensions.DepenencyInjection程序包里面,它有一個(gè)默認(rèn)的實(shí)現(xiàn):ServiceCollection。

public class ServiceCollection : IServiceCollection {private readonly List<ServiceDescriptor> _descriptors = new List<ServiceDescriptor>();public int Count => _descriptors.Count;public bool IsReadOnly => false;public ServiceDescriptor this[int index]{get{return _descriptors[index];}set{_descriptors[index] = value;}}// ... }

它有一個(gè)私有的List集合:_descriptors,里面是ServiceDescriptor。

讓我們從創(chuàng)建一個(gè)ServiceCollection,然后注冊(cè)兩個(gè)服務(wù)。

static void Main(string[] args) {var serviceCollection = new ServiceCollection();serviceCollection.AddSingleton<ClassA>();serviceCollection.AddSingleton<IThing, ClassB>();Console.WriteLine("Done"); }

在前面的代碼中,我們已經(jīng)使用AddSingleton方法注冊(cè)了兩個(gè)服務(wù),這不是IServiceCollection接口定義的方法,也不在ServiceCollection上,這是IServiceCollection的擴(kuò)展方法,這個(gè)方法在ServiceCollectionServiceExtensions的擴(kuò)展類中,接下來,我會(huì)介紹這個(gè)方法是如何注冊(cè)服務(wù)的,不過這之前,我們首先回顧下服務(wù)生命周期的概念。

服務(wù)生命周期

在Microsoft依賴項(xiàng)注入框架中,我們可以使用三種生命周期注冊(cè)服務(wù),分別是單例(Singleton)、瞬時(shí)(Transient)、作用域(Scoped),在上面的代碼中,我使用了AddSingleton()來注冊(cè)服務(wù)。

使用Singleton服務(wù)的優(yōu)點(diǎn)是我們不會(huì)創(chuàng)建多個(gè)服務(wù)實(shí)例,只會(huì)創(chuàng)建一個(gè)實(shí)例,保存到DI容器中,直到程序退出,這不僅效率高,而且性能高,但是有一個(gè)要注意的點(diǎn),如果在多線程中使用了Singleton,要考慮線程安全的問題,保證它不會(huì)有沖突。

瞬時(shí)(Transient)和單例(Singleton)模式是相反的,每次使用時(shí),DI容器都是創(chuàng)建一個(gè)新的實(shí)例。

作用域(Scoped),在一個(gè)作用域內(nèi),會(huì)使用同一個(gè)實(shí)例,像EF Core的DbContext上下文就被注冊(cè)為作用域服務(wù)。

我們注冊(cè)服務(wù)時(shí)會(huì)發(fā)生什么?

在上面的代碼中,我已經(jīng)注冊(cè)了兩個(gè)單例服務(wù)。

serviceCollection.AddSingleton<ClassA>(); serviceCollection.AddSingleton<IThing, ClassB>();

這是最終的AddSingleton方法:

public static IServiceCollection AddSingleton(this IServiceCollection services,Type serviceType,Type implementationType) {if (services == null){throw new ArgumentNullException(nameof(services));}if (serviceType == null){throw new ArgumentNullException(nameof(serviceType));}if (implementationType == null){throw new ArgumentNullException(nameof(implementationType));}return Add(services, serviceType, implementationType, ServiceLifetime.Singleton); }

我們可以看到AddSingleton方法調(diào)用了私有的Add方法,并且傳入了一個(gè)生命周期的枚舉值ServiceLifetime.Singleton。

讓我們看一下Add方法的工作原理:

private static IServiceCollection Add(IServiceCollection collection,Type serviceType,Type implementationType,ServiceLifetime lifetime) {var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);collection.Add(descriptor);return collection; }

它創(chuàng)建一個(gè)新的ServiceDescriptor實(shí)例,傳入服務(wù)類型,實(shí)現(xiàn)類型(可能與服務(wù)類型相同)和生命周期,然后調(diào)用Add方法添加到列表中。

之前,我們了解到IServiceCollection本質(zhì)上是包裝了List <ServiceDescriptor>, ServiceDescriptor類很簡(jiǎn)單,代表一個(gè)注冊(cè)的服務(wù),包括其服務(wù)類型,實(shí)現(xiàn)類型和生命周期。

實(shí)例注冊(cè)

我們也可以手動(dòng)new一個(gè)實(shí)例,然后傳入到AddSingleton()方法中:

var myInstance = new ClassB(); serviceCollection.AddSingleton<IThing>(myInstance);

使用 ServiceDescriptor

我們還可以手動(dòng)定義一個(gè)ServiceDescriptor,然后直接添加到IServiceCollection中。

var descriptor = new ServiceDescriptor(typeof(IThing), typeof(ClassB), ServiceLifetime.Singleton); serviceCollection.Add(descriptor);

總結(jié)

在本文中,介紹了.NET中的DI的一些核心知識(shí),可以直接創(chuàng)建ServiceCollection來使用Microsoft DI框架,了解了IServiceCollection上的AddSingleton擴(kuò)展方法是如何工作,以及它們最終創(chuàng)建了一個(gè)ServiceDescriptor,然后添加到一個(gè)ServiceCollection包裝的List集合中。

原文鏈接:?https://www.stevejgordon.co.uk/aspnet-core-dependency-injection-what-is-the-iservicecollection

歡迎掃碼關(guān)注我們的公眾號(hào) 【全球技術(shù)精選】,專注國(guó)外優(yōu)秀博客的翻譯和開源項(xiàng)目分享,也可以添加QQ群 897216102

總結(jié)

以上是生活随笔為你收集整理的探索 .NET Core 依赖注入的 IServiceCollection的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。