【问题标题】:How IServiceProvider get injected by default?默认情况下如何注入 IServiceProvider?
【发布时间】:2021-12-30 09:06:53
【问题描述】:

我们可以通过以下方式访问IServiceProvider

public class ProductService
{
    private readonly IProductRepository _productRepository;
    public ProductService(IServiceProvider serviceProvider)
    {
       _productRepository = serviceProvider.GetRequiredService<IProductRepository>();  
    }
    ...
}

所以很明显.net默认注册IServiceProvider为服务,但我查了源码:https://github.com/aspnet/Hosting/blob/master/src/Microsoft.Extensions.Hosting/HostBuilder.cs#L198

private void CreateServiceProvider() {
   var services = new ServiceCollection();
   services.AddSingleton(_hostingEnvironment);
   services.AddSingleton(_hostBuilderContext);
   services.AddSingleton(_appConfiguration); 
   services.AddSingleton<IApplicationLifetime, ApplicationLifetime>();
   services.AddSingleton<IHostLifetime, ConsoleLifetime>();
   services.AddSingleton<IHost, Host>();
   services.AddOptions();
   services.AddLogging();

   foreach (var configureServicesAction in _configureServicesActions) {
      configureServicesAction(_hostBuilderContext, services);
   }

   var containerBuilder = _serviceProviderFactory.CreateBuilder(services);

   foreach (var containerAction in _configureContainerActions) {
      containerAction.ConfigureContainer(_hostBuilderContext, containerBuilder);
   }

   _appServices = _serviceProviderFactory.CreateServiceProvider(containerBuilder);   // _appServices is IServiceProvider 

   if (_appServices == null) {
      throw new InvalidOperationException($"The IServiceProviderFactory returned a null IServiceProvider.");
   }
}

所以我们可以看到例如:

services.AddSingleton(_appConfiguration); 

注册IConfiguration(后台ConfigurationRoot实例),这就是我们可以在startup.cs中使用它的原因:

public class Startup {
   public Startup(IConfiguration configuration) { 
      Configuration = configuration;
   }
   public IConfiguration Configuration { get; }

但是我在任何地方都看不到源代码寄存器_appServices(IServiceProvider),源代码中没有像services.AddSingleton(_appServices);这样的东西

那么我们如何仍然可以自动访问IServiceProvider?或者我一定是错过了某个地方,源代码确实在其他地方注册了IServiceProvider

【问题讨论】:

    标签: c# .net-core dependency-injection


    【解决方案1】:

    BuildServiceProvider 扩展最终在服务集合上被调用时

    /// <summary>
    /// Creates a <see cref="ServiceProvider"/> containing services from the provided <see cref="IServiceCollection"/>
    /// optionally enabling scope validation.
    /// </summary>
    /// <param name="services">The <see cref="IServiceCollection"/> containing service descriptors.</param>
    /// <param name="options">
    /// Configures various service provider behaviors.
    /// </param>
    /// <returns>The <see cref="ServiceProvider"/>.</returns>
    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));
        }
    
        return new ServiceProvider(services, options);
    }
    

    Source

    ServiceProvider 实例将自身添加为服务。

    internal ServiceProvider(ICollection<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
    {
        // note that Root needs to be set before calling GetEngine(), because the engine may need to access Root
        Root = new ServiceProviderEngineScope(this, isRootScope: true);
        _engine = GetEngine();
        _createServiceAccessor = CreateServiceAccessor;
        _realizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
    
        CallSiteFactory = new CallSiteFactory(serviceDescriptors);
        // The list of built in services that aren't part of the list of service descriptors
        // keep this in sync with CallSiteFactory.IsService
        CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
        CallSiteFactory.Add(typeof(IServiceScopeFactory), new ConstantCallSite(typeof(IServiceScopeFactory), Root));
        CallSiteFactory.Add(typeof(IServiceProviderIsService), new ConstantCallSite(typeof(IServiceProviderIsService), CallSiteFactory));
    
        if (options.ValidateScopes)
        {
            _callSiteValidator = new CallSiteValidator();
        }
    
        if (options.ValidateOnBuild)
        {
            List<Exception> exceptions = null;
            foreach (ServiceDescriptor serviceDescriptor in serviceDescriptors)
            {
                try
                {
                    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());
            }
        }
    
        DependencyInjectionEventSource.Log.ServiceProviderBuilt(this);
    }
    

    Source

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-29
      • 1970-01-01
      • 2010-12-02
      • 2012-11-24
      • 1970-01-01
      • 2018-07-30
      • 2018-01-18
      • 2019-12-20
      相关资源
      最近更新 更多