Home > other >  How IServiceProvider get injected by default?
How IServiceProvider get injected by default?

Time:12-31

we can access the IServiceProvider as:

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

so it is obvious that .net registers IServiceProvider as a service by default, but I checked the source code: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.");
   }
}

so we can see that for example:

services.AddSingleton(_appConfiguration); 

register IConfiguration (ConfigurationRoot instance under the hood), that's why we can use it in the startup.cs:

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

but I can't see the source code register _appServices(IServiceProvider) anywhere, there is no sth like services.AddSingleton(_appServices); in the source code

So how we still can access IServiceProvider automatically? or I must be missing somewhere, the source code does register IServiceProvider somewhere else?

CodePudding user response:

When BuildServiceProvider extension is eventually invoked on the service collection

/// <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

The ServiceProvider instance, adds itself as a service.

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

  • Related