默认情况下 IServiceProvider 是如何注入的?

How IServiceProvider get injected by default?

我们可以访问 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); 

注册 IConfigurationConfigurationRoot 底层实例),这就是我们可以在 startup.cs:

中使用它的原因
public class Startup {
   public Startup(IConfiguration configuration) { 
      Configuration = configuration;
   }
   public IConfiguration Configuration { get; }

但是我在任何地方都看不到源代码寄存器_appServices(IServiceProvider),源代码

中没有services.AddSingleton(_appServices);之类的东西

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

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