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

歡迎訪問 生活随笔!

生活随笔

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

asp.net

探索 .NET Core 依赖注入的 IServiceProvider

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

在上一篇文章中,我們學(xué)習(xí)了Microsoft.Extensions.DependencyInjection中的IServiceCollection,包括服務(wù)注冊轉(zhuǎn)換為ServiceDescriptors,然后添加到集合中。

探索 .NET Core 依賴注入的 IServiceCollection[1]

在本文中,我們會(huì)學(xué)習(xí) IServiceProvider,了解它是什么,以及它是怎么創(chuàng)建出來的,我們將根據(jù)上一篇文章中創(chuàng)建的IServiceCollection來學(xué)習(xí)如何構(gòu)建IServiceProvider。

什么是 IServiceProvider?

IServiceProvider會(huì)根據(jù)程序的要求在運(yùn)行時(shí)解析服務(wù)類型的實(shí)例,ServiceProvider來保證已解析的服務(wù)在預(yù)期的生命周期內(nèi)有效,這個(gè)實(shí)現(xiàn)設(shè)計(jì)的非常高效,所以服務(wù)的解析速度非常快。

構(gòu)建一個(gè) IServiceProvider

首先,當(dāng)我們把服務(wù)都添加到 IServiceCollection ,接下來會(huì)構(gòu)建一個(gè)IServiceProvider, 它能夠提供我們程序中所依賴服務(wù)的實(shí)例,本質(zhì)上它包裝了 IServiceCollection。

通過調(diào)用 BuildServiceProvider(IServiceCollection上的一個(gè)擴(kuò)展方法)完成構(gòu)建:

var serviceCollection = new ServiceCollection(); serviceCollection.AddSingleton<ClassA>(); serviceCollection.AddSingleton<IThing, ClassB>();var serviceProvider = serviceCollection.BuildServiceProvider();

當(dāng)我們沒有傳入任何參數(shù)時(shí),它會(huì)創(chuàng)建一個(gè) ServiceProviderOptions 的一個(gè)默認(rèn)實(shí)例:

public static class ServiceCollectionContainerBuilderExtensions { public static ServiceProvider BuildServiceProvider(this IServiceCollection services){return services.BuildServiceProvider(ServiceProviderOptions.Default);}

ServiceProviderOptions 有兩個(gè)屬性,在本文后邊的內(nèi)容,我會(huì)詳細(xì)介紹這些:

public class ServiceProviderOptions {public bool ValidateScopes { get; set; }public bool ValidateOnBuild { get; set; } }

BuildServiceProvider 的方法內(nèi)部是這樣的:

public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options) {if (services == null){throw new ArgumentNullException(nameof(services));}if (options == null){throw new ArgumentNullException(nameof(options));}IServiceProviderEngine engine; #if !NETCOREAPPengine = new DynamicServiceProviderEngine(services); #elseif (RuntimeFeature.IsDynamicCodeCompiled){engine = new DynamicServiceProviderEngine(services);}else{// Don't try to compile Expressions/IL if they are going to get interpretedengine = new RuntimeServiceProviderEngine(services);} #endifreturn new ServiceProvider(services, engine, options); }

最終,它會(huì)創(chuàng)建并返回一個(gè) ServiceProvider。

ServiceProviderEngine

在上面的代碼中,ServiceProvider選擇應(yīng)該使用哪個(gè) engine, engine 是一個(gè)組件,它的功能是負(fù)責(zé) DI容器中服務(wù)實(shí)例的創(chuàng)建,然后把實(shí)例注入到其他服務(wù)中。

這些是 IServiceProviderEngine 的四個(gè)實(shí)現(xiàn):

?Dynamic?Runtime?ILEmit?Expressions (System.Linq.Expressions)

從上面的代碼中,我們可以看到在大多數(shù)情況下會(huì)使用 DynamicServiceProviderEngine,僅在目標(biāo)框架不支持動(dòng)態(tài)代碼編譯的情況下,才使用RuntimeServiceProviderEngine,DynamicServiceProviderEngine 會(huì)使用 ILEmit 或者 Expressions 來解析服務(wù)。

我們看一下 ServiceProviderEngine 的構(gòu)造函數(shù)的內(nèi)容:

protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors) {_createServiceAccessor = CreateServiceAccessor;Root = new ServiceProviderEngineScope(this);RuntimeResolver = new CallSiteRuntimeResolver();CallSiteFactory = new CallSiteFactory(serviceDescriptors);CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite());RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>(); }

它創(chuàng)建一個(gè) Root ServiceProviderEngineScope,然后傳入this, scopes限制了服務(wù)的生命周期,最常見的就是,.Net Core 收到一個(gè)接口請求時(shí),它創(chuàng)建的服務(wù)就是 Scope 類型。

這種情況下,我們注冊的單例服務(wù),它都是從 Root Scope 返回的。

然后創(chuàng)建一個(gè) CallSiteRuntimeResolver,我會(huì)在接下來的文章介紹它。

最后,在上面的構(gòu)造函數(shù)中,將創(chuàng)建一個(gè)新的ConcurrentDictionary來保存有關(guān)服務(wù)的信息,按需設(shè)計(jì),只有開始使用這些服務(wù)時(shí),它才會(huì)開始創(chuàng)建,如果有些服務(wù)注冊了,但是沒有使用的話,那么它永遠(yuǎn)不會(huì)創(chuàng)建。

ServiceProvider 構(gòu)造方法

讓我們回到 BuildServiceProvider 方法的最后一行,它會(huì)傳入 IServiceCollection, Engine和ServiceProviderOptions:

internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngine engine, ServiceProviderOptions options) {_engine = engine;if (options.ValidateScopes){_engine.InitializeCallback(this);_callSiteValidator = new CallSiteValidator();}if (options.ValidateOnBuild){List<Exception> exceptions = null;foreach (ServiceDescriptor serviceDescriptor in serviceDescriptors){try{_engine.ValidateService(serviceDescriptor);}catch (Exception e){exceptions = exceptions ?? new List<Exception>();exceptions.Add(e);}}if (exceptions != null){throw new AggregateException("Some services are not able to be constructed", exceptions.ToArray());}} }

在上面的代碼中,我們可以看到在構(gòu)造函數(shù)中使用了ServiceProviderOptions, 當(dāng)ValidateScopes為true時(shí),ServiceProvider會(huì)傳入this調(diào)用 engine 的 InitializeCallback方法,它還創(chuàng)建一個(gè)新的CallSiteValidator。

如果 ValidateOnBuild 為true的話,它會(huì)檢查DI容器中已注冊的所有服務(wù),遍歷了ServiceDescriptor 集合,然后調(diào)用 ValidateService, 檢查服務(wù),并且這里捕獲了異常,如果有錯(cuò)誤,會(huì)拋出一個(gè)聚合的異常信息。

那么在程序中使用 ValidateOnBuild,可以保證在程序啟動(dòng)時(shí)就檢查已注冊的錯(cuò)誤服務(wù),而不是在首次解析服務(wù)時(shí)在運(yùn)行時(shí)捕獲異常,這個(gè)可以很好的幫助排除問題。

ValidateService 的方法內(nèi)部如下:

public void ValidateService(ServiceDescriptor descriptor) {if (descriptor.ServiceType.IsGenericType && !descriptor.ServiceType.IsConstructedGenericType){return;}try{ServiceCallSite callSite = CallSiteFactory.GetCallSite(descriptor, new CallSiteChain());if (callSite != null){_callback?.OnCreate(callSite);}}catch (Exception e){throw new InvalidOperationException($"Error while validating the service descriptor '{descriptor}': {e.Message}", e);} }

總結(jié)

在本文中,我們重點(diǎn)介紹了如何從IServiceCollection來構(gòu)建IServiceProvider,我們探索了一些實(shí)現(xiàn)細(xì)節(jié),以了解如何應(yīng)用ValidateScopes和ValidateOnBuild ServiceProviderOptions,我們在這篇文章中談到了很多內(nèi)部代碼,但作為庫的使用者,您不必?fù)?dān)心這些細(xì)節(jié)。

最重要的一點(diǎn)是,在IServiceCollection上調(diào)用BuildServiceProvider之后,將創(chuàng)建默認(rèn)的ServiceProvider。

var serviceProvider = serviceCollection.BuildServiceProvider();

也可以傳入 ServiceProviderOptions

var serviceProviderWithOptions = serviceCollection.BuildServiceProvider(new ServiceProviderOptions {ValidateOnBuild = true,ValidateScopes = true });

原文鏈接:?https://www.stevejgordon.co.uk/aspnet-core-dependency-injection-what-is-the-iserviceprovider-and-how-is-it-built[2]

最后

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

總結(jié)

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

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