<sub id="gqw76"><listing id="gqw76"></listing></sub>
      <sub id="gqw76"><listing id="gqw76"></listing></sub>

    1. <form id="gqw76"><legend id="gqw76"></legend></form>
    2. 探索 .NET Core 依賴注入的 IServiceProvider

      在上一篇文章中,我們學習了Microsoft.Extensions.DependencyInjection中的IServiceCollection,包括服務注冊轉換為ServiceDescriptors,然后添加到集合中。

      探索 .NET Core 依賴注入的 IServiceCollection

      在本文中,我們會學習 IServiceProvider,了解它是什么,以及它是怎么創建出來的,我們將根據上一篇文章中創建的IServiceCollection來學習如何構建IServiceProvider。

      什么是 IServiceProvider?

      IServiceProvider會根據程序的要求在運行時解析服務類型的實例,ServiceProvider來保證已解析的服務在預期的生命周期內有效,這個實現設計的非常高效,所以服務的解析速度非常快。

      構建一個 IServiceProvider

      首先,當我們把服務都添加到 IServiceCollection ,接下來會構建一個IServiceProvider, 它能夠提供我們程序中所依賴服務的實例,本質上它包裝了 IServiceCollection。

      通過調用 BuildServiceProvider(IServiceCollection上的一個擴展方法)完成構建:

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

      當我們沒有傳入任何參數時,它會創建一個 ServiceProviderOptions 的一個默認實例:

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

      ServiceProviderOptions 有兩個屬性,在本文后邊的內容,我會詳細介紹這些:

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

      BuildServiceProvider 的方法內部是這樣的:

      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 !NETCOREAPP
          engine = new DynamicServiceProviderEngine(services);
      #else
          if (RuntimeFeature.IsDynamicCodeCompiled)
          {
              engine = new DynamicServiceProviderEngine(services);
          }
          else
          {
              // Don't try to compile Expressions/IL if they are going to get interpreted
              engine = new RuntimeServiceProviderEngine(services);
          }
      #endif
          return new ServiceProvider(services, engine, options);
      }
      

      最終,它會創建并返回一個 ServiceProvider。

      ServiceProviderEngine

      在上面的代碼中,ServiceProvider選擇應該使用哪個 engine, engine 是一個組件,它的功能是負責 DI容器中服務實例的創建,然后把實例注入到其他服務中。

      這些是 IServiceProviderEngine 的四個實現:

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

      從上面的代碼中,我們可以看到在大多數情況下會使用 DynamicServiceProviderEngine,僅在目標框架不支持動態代碼編譯的情況下,才使用RuntimeServiceProviderEngine,DynamicServiceProviderEngine 會使用 ILEmit 或者 Expressions 來解析服務。

      我們看一下 ServiceProviderEngine 的構造函數的內容:

      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>>();
      }
      

      它創建一個 Root ServiceProviderEngineScope,然后傳入this, scopes限制了服務的生命周期,最常見的就是,.Net Core 收到一個接口請求時,它創建的服務就是 Scope 類型。

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

      然后創建一個 CallSiteRuntimeResolver,我會在接下來的文章介紹它。

      最后,在上面的構造函數中,將創建一個新的ConcurrentDictionary來保存有關服務的信息,按需設計,只有開始使用這些服務時,它才會開始創建,如果有些服務注冊了,但是沒有使用的話,那么它永遠不會創建。

      ServiceProvider 構造方法

      讓我們回到 BuildServiceProvider 方法的最后一行,它會傳入 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());
              }
          }
      }
      

      在上面的代碼中,我們可以看到在構造函數中使用了ServiceProviderOptions, 當ValidateScopes為true時,ServiceProvider會傳入this調用 engine 的 InitializeCallback方法,它還創建一個新的CallSiteValidator。

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

      那么在程序中使用 ValidateOnBuild,可以保證在程序啟動時就檢查已注冊的錯誤服務,而不是在首次解析服務時在運行時捕獲異常,這個可以很好的幫助排除問題。

      ValidateService 的方法內部如下:

      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);
          }
      }
      

      總結

      在本文中,我們重點介紹了如何從IServiceCollection來構建IServiceProvider,我們探索了一些實現細節,以了解如何應用ValidateScopes和ValidateOnBuild ServiceProviderOptions,我們在這篇文章中談到了很多內部代碼,但作為庫的使用者,您不必擔心這些細節。

      最重要的一點是,在IServiceCollection上調用BuildServiceProvider之后,將創建默認的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

      最后

      歡迎掃碼關注我們的公眾號 【全球技術精選】,專注國外優秀博客的翻譯和開源項目分享,也可以添加QQ群 897216102

      posted @ 2021-03-01 19:06  SpringLeee  閱讀(11)  評論(0編輯  收藏
      最新chease0ldman老人|无码亚洲人妻下载|大香蕉在线看好吊妞视频这里有精品www|亚洲色情综合网

        <sub id="gqw76"><listing id="gqw76"></listing></sub>
        <sub id="gqw76"><listing id="gqw76"></listing></sub>

      1. <form id="gqw76"><legend id="gqw76"></legend></form>