How to get an instance of IServiceProvider in .NET Core?

128,361

Solution 1

This is the default implementation of IServiceCollection from Microsoft: https://github.com/aspnet/DependencyInjection/blob/master/src/DI/ServiceCollection.cs

Looking at the code then you should be able to get an IServiceCollection simply by calling:

var serviceCollection = new Microsoft.Extensions.DependencyInjection.ServiceCollection();

Hope that helps :)

Solution 2

As goaty mentioned it's enough to create new ServiceCollection. Here's example class which can be used to access DI container in .NET Core:

public static class ServiceProviderFactory
{
    public static IServiceProvider ServiceProvider { get; }

    static ServiceProviderFactory()
    {
        HostingEnvironment env = new HostingEnvironment();
        env.ContentRootPath = Directory.GetCurrentDirectory();
        env.EnvironmentName = "Development";

        Startup startup = new Startup(env);
        ServiceCollection sc = new ServiceCollection();
        startup.ConfigureServices(sc);
        ServiceProvider = sc.BuildServiceProvider();
    }
}

Startup class is taken from tested project so the service registrations don't need to be repeated.

Then in test class simply use:

var foo = ServiceProviderFactory.ServiceProvider.GetServices(typeof(IFoo));

Solution 3

To get access to existing DI of ASP.NET Core application e.g. in some controller, you should just resolve it in a constructor. Example with some manager and workers:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
   services.AddMvc();

   services.AddSingleton<IFooManager, FooManager>();
   services.AddTransient<IFooWorker, FooWorker>();
}

Manually resolve workers for manager:

public class FooManager: IFooManager
{
    private readonly IServiceProvider _serviceProvider;

    public FooManager(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public void Start()
    {
        var w1 = _serviceProvider.GetRequiredService<IFooWorker>();  // new instance of FooWorker
        var w2 = _serviceProvider.GetRequiredService<IFooWorker>();  // new instance of FooWorker
    }
}

Solution 4

First you need to install the Microsoft.Extensions.DependencyInjection NuGet package. (docs, API, API)

Then you create a new ServiceCollection and method chain it with the BuildServiceProvider method. In between that you can also register any service providers.

var serviceProvider = new ServiceCollection()
    .AddSingleton<IFooService, FooService>()
    .BuildServiceProvider();

Solution 5

Here is an updated approach:

var host = Host.CreateDefaultBuilder().ConfigureWebHostDefaults(builder =>
{
    builder.ConfigureAppConfiguration((hostingContext, config) =>
    {
        var env = hostingContext.HostingEnvironment;
        env.ContentRootPath = Directory.GetCurrentDirectory();
        env.EnvironmentName = "Development";
    });

    builder.UseStartup<Startup>();
}).Build();

Example usage:

host.Services.GetService<IFoo>();
Share:
128,361

Related videos on Youtube

Arkadiusz Kałkus
Author by

Arkadiusz Kałkus

I’m a full-stack developer specialized in the design, and implementation of corporate web applications. I put emphasis on S.O.L.I.D. craftsmanship and strive to keep my code clean. Because I know how expensive technical debt can be. Because I understand my job is not to write code but to solve problems. Because I want to help people to be more effective through the software.

Updated on February 02, 2022

Comments

  • Arkadiusz Kałkus
    Arkadiusz Kałkus over 2 years

    IServiceProvider is an interface with single method:

    object GetService(Type serviceType);
    

    It's used to create instances of types registered in .NET Core native DI container.

    An instance of IServiceProvider itself can be obtained by calling a BuildServiceProvider method of an IServiceCollection. IServiceCollection is a parameter of ConfigureServices method in a Startup class. It seems to be magically called with an instance of IServiceCollection by the framework.

    I want to create an instance of IServiceProvider without having Setup method at all. I need it to resolve dependencies in an integration test assembly. Is it possible to get it at all in this scenario?

  • Chris Marisic
    Chris Marisic over 5 years
    Great answer for showing you have to activate the ServiceCollection, build the provider, and then explicitly capture the reference to it.
  • Gerry
    Gerry over 5 years
    It seems a bit annoying to me that I have to pass an IServiceProvider around. Microsoft should have at least made a static/singleton IServiceProvider.
  • JamesHoux
    JamesHoux over 4 years
    @Gerry Microsoft didn't do that, because passing an instanced object around is backwards compatible with singletons -- but not the other way around. Additionally, many people misuse/abuse singletons, and its not good to encourage the use of something people abuse. If you want a static singleton service for your app, you can easily create your own singleton to encapsulate the IServiceProvider and then access it wherever you want via your own singleton. That's the backwards-compatibility part.
  • Neutrino
    Neutrino over 4 years
    I don't see how that's useful. The new ServiceCollection is empty and won't contain any of the service registrations that would be created by Startup.ConfigureServices so the ServiceProvider built from it won't be capable of providing anything at all.
  • Neutrino
    Neutrino over 4 years
    I don't think this is useful either. Here a new Startup instance is used to configure the ServiceCollection but this will contain different instances of any singletons used by the application, so again this does not provide access to a ServiceProvider that enables you to access the services configured for an application.
  • MikeBeaton
    MikeBeaton over 4 years
    @Neutrino I think what you want to do is NOT quite what the OP here wants to do. But... if you want to instantiate a running instance of your app and then test it while also having access to the running app's service provider, then look into Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory. Or if you want to manually resolve a class of a given type within the app, but using explicit code to ask for the object rather than relying on the constructor injection chain, then look here: stackoverflow.com/a/32461714/795690 .
  • Rafael
    Rafael over 4 years
    This doesn't even compile in .NET Core? cannot convert from 'Microsoft.Extensions.Hosting.Internal.HostingEnvironment' to 'Microsoft.Extensions.Configuration.IConfiguration'
  • Abhishek
    Abhishek about 4 years
    Quite useful actually @Neutrino - I built some extensions for configuration and need to test them
  • Andree
    Andree over 3 years
    This is not a good approach for simple reason. As you build your own ServiceProvider, you no longer can ensure the registred singletons will be still singletons as there will be two service providers each providing their instances of singletons. docs.microsoft.com/en-us/aspnet/core/fundamentals/…