573

How do I manually resolve a type using the ASP.NET Core MVC built-in dependency injection framework?

Setting up the container is easy enough:

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddTransient<ISomeService, SomeConcreteService>();
}

But how can I resolve ISomeService without performing injection? For example, I want to do this:

ISomeService service = services.Resolve<ISomeService>();

There are no such methods in IServiceCollection.

Steven
  • 166,672
  • 24
  • 332
  • 435
Dave New
  • 38,496
  • 59
  • 215
  • 394

9 Answers9

879

The IServiceCollection interface is used for building a dependency injection container. After it's fully built, it gets composed to an IServiceProvider instance which you can use to resolve services. You can inject an IServiceProvider into any class. The IApplicationBuilder and HttpContext classes can provide the service provider as well, via their ApplicationServices or RequestServices properties respectively.

IServiceProvider defines a GetService(Type type) method to resolve a service:

var service = (IFooService)serviceProvider.GetService(typeof(IFooService));

There are also several convenience extension methods available, such as serviceProvider.GetService<IFooService>() (add a using for Microsoft.Extensions.DependencyInjection).

Resolving services inside the startup class

Injecting dependencies

The runtime's hosting service provider can inject certain services into the constructor of the Startup class, such as IConfiguration, IWebHostEnvironment (IHostingEnvironment in pre-3.0 versions), ILoggerFactory and IServiceProvider. Note that the latter is an instance built by the hosting layer and contains only the essential services for starting up an application.

The ConfigureServices() method does not allow injecting services, it only accepts an IServiceCollection argument. This makes sense because ConfigureServices() is where you register the services required by your application. However you can use services injected in the startup's constructor here, for example:

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

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    // Use Configuration here
}

Any services registered in ConfigureServices() can then be injected into the Configure() method; you can add an arbitrary number of services after the IApplicationBuilder parameter:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IFooService>();
}

public void Configure(IApplicationBuilder app, IFooService fooService)
{
    fooService.Bar();
}

Manually resolving dependencies

If you need to manually resolve services, you should preferably use the ApplicationServices provided by IApplicationBuilder in the Configure() method:

public void Configure(IApplicationBuilder app)
{
    var serviceProvider = app.ApplicationServices;
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}

It is possible to pass and directly use an IServiceProvider in the constructor of your Startup class, but as above this will contain a limited subset of services, and thus has limited utility:

public Startup(IServiceProvider serviceProvider)
{
    var hostingEnv = serviceProvider.GetService<IWebHostEnvironment>();
}

If you must resolve services in the ConfigureServices() method, a different approach is required. You can build an intermediate IServiceProvider from the IServiceCollection instance which contains the services which have been registered up to that point:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IFooService, FooService>();

    // Build the intermediate service provider
    var sp = services.BuildServiceProvider();

    // This will succeed.
    var fooService = sp.GetService<IFooService>();
    // This will fail (return null), as IBarService hasn't been registered yet.
    var barService = sp.GetService<IBarService>();
}

Please note: Generally you should avoid resolving services inside the ConfigureServices() method, as this is actually the place where you're configuring the application services. Sometimes you just need access to an IOptions<MyOptions> instance. You can accomplish this by binding the values from the IConfiguration instance to an instance of MyOptions (which is essentially what the options framework does):

public void ConfigureServices(IServiceCollection services)
{
    var myOptions = new MyOptions();
    Configuration.GetSection("SomeSection").Bind(myOptions);
}

Or use an overload for AddSingleton/AddScoped/AddTransient:

// Works for AddScoped and AddTransient as well
services.AddSingleton<IBarService>(sp =>
{
    var fooService = sp.GetRequiredService<IFooService>();
    return new BarService(fooService);
}

Manually resolving services (aka Service Locator) is generally considered an anti-pattern. While it has its use-cases (for frameworks and/or infrastructure layers), you should avoid it as much as possible.

Henk Mollema
  • 44,194
  • 12
  • 93
  • 104
  • 22
    @HenkMollema but what if i can't have anything injected, I mean I can't have `IServiceCollection` injected, some class that is being created manually(_out of middle ware scope_), a scheduler in my case, which periodically needs some services to generate and send an email. – Merdan Gochmuradov Nov 29 '16 at 07:24
  • 75
    *warning* if you need to resolve services in `ConfigureServices` and that service is a singleton it will be a different singleton to the one your `Controller`s use! I assume this is because it uses a different `IServiceProvider` - to avoid this do NOT resolve via `BuildServiceProvider` and instead move your lookup of the singleton from `ConfigureServices` to `Configure(..other params, IServiceProvider serviceProvider)` in `Startup.cs` – wal Mar 24 '17 at 07:21
  • 3
    @wal good point. Because it's a different `IServiceProvider` instance it will create a new singleton instance. You could avoid this by returning the service provider instance from the `ConfigureServices` method so that will be the container your application uses as well. – Henk Mollema Mar 24 '17 at 08:38
  • 1
    Invoking `collection.BuildServiceProvider();` was what I needed, thanks! – Chris Marisic May 02 '17 at 22:25
  • 3
    @HenkMollema how do you make it work with only one service provider instance? Typically, you would 1) Register some of your dependencies 2) build an interim service provider instance 3) Use that service provider to resolve something you need to register some other dependencies. Afterwards, you can't return the interim instance, since it's missing some of your dependencies (registered in 3). Am I missing something? – Filip Aug 21 '18 at 13:35
  • It seems `public Startup(IServiceProvider serviceProvider)` is not working. When I try this I get a nice exception saying `Unable to resolve service for type 'System.IServiceProvider'` – Jérôme MEVEL Mar 13 '20 at 14:07
  • 2
    "Any services registered in ConfigureServices() can then be injected into the Configure() method; you can add an arbitrary number of services after the IApplicationBuilder parameter" - That line changed my life.Thank you very much. Is that in the docs somewhere? – Eakan Gopalakrishnan Dec 08 '20 at 21:39
  • But when should I use `IApplicationBuilder ` vs `IServiceProvider` ? – Royi Namir Apr 18 '21 at 07:28
  • Can you create a new IServiceCollection for the types you want to resolve in ConfigureServices and build a provider of that? If so, then you wouldn't have two service providers that contain the same types. – schmiddy98 Apr 06 '22 at 16:02
  • congrats @HenkMollema this is very good and comprehensive answer. may you consider update the answer to the latest top-level statements feature of the dotnet – iBener Jan 11 '23 at 08:08
202

Manually resolving instances involves using the IServiceProvider interface:

Resolving Dependency in Startup.ConfigureServices

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IMyService, MyService>();

    var serviceProvider = services.BuildServiceProvider();
    var service = serviceProvider.GetService<IMyService>();
}

Resolving Dependencies in Startup.Configure

public void Configure(
    IApplicationBuilder application,
    IServiceProvider serviceProvider)
{
    // By type.
    var service1 = (MyService)serviceProvider.GetService(typeof(MyService));

    // Using extension method.
    var service2 = serviceProvider.GetService<MyService>();

    // ...
}

Resolving Dependencies in Startup.Configure in ASP.NET Core 3

public void Configure(
    IApplicationBuilder application,
    IWebHostEnvironment webHostEnvironment)
{
    application.ApplicationServices.GetService<MyService>();
}

Using Runtime Injected Services

Some types can be injected as method parameters:

public class Startup
{
    public Startup(
        IHostingEnvironment hostingEnvironment,
        ILoggerFactory loggerFactory)
    {
    }

    public void ConfigureServices(
        IServiceCollection services)
    {
    }

    public void Configure(
        IApplicationBuilder application,
        IHostingEnvironment hostingEnvironment,
        IServiceProvider serviceProvider,
        ILoggerFactory loggerfactory,
        IApplicationLifetime applicationLifetime)
    {
    }
}

Resolving Dependencies in Controller Actions

[HttpGet("/some-action")]
public string SomeAction([FromServices] IMyService myService) => "Hello";
Muhammad Rehan Saeed
  • 35,627
  • 39
  • 202
  • 311
  • 2
    @AfsharMohebbi the `GetService` which is generic is an extension method in `Microsoft.Extensions.DependencyInjection` namespace. – ahmadali shafiee Nov 19 '17 at 16:06
  • About Extension Methods: An extension method is a static method that adds funcionality to a class, you could declare public static TheReturnType TheMethodName(this TheTypeYouExtend theTypeYouExtend { // BODY} and then you could use it like: TheTypeYouExtend.TheMethodName(); That has become a very common aproach with .NET Core, so that developers can extend base functionality... good examples here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods – Juan Jun 03 '18 at 09:44
  • `[FromServices]`is almost to good to be true. Pinch me! Am I dreaming? – FatAlbert Feb 14 '23 at 07:45
26

If you generate an application with a template you are going to have something like this on the Startup class:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);

    services.AddMvc();
}

You can then add dependencies there, for example:

services.AddTransient<ITestService, TestService>();

If you want to access ITestService on your controller you can add IServiceProvider on the constructor and it will be injected:

public HomeController(IServiceProvider serviceProvider)

Then you can resolve the service you added:

var service = serviceProvider.GetService<ITestService>();

Note that to use the generic version you have to include the namespace with the extensions:

using Microsoft.Extensions.DependencyInjection;

ITestService.cs

public interface ITestService
{
    int GenerateRandom();
}

TestService.cs

public class TestService : ITestService
{
    public int GenerateRandom()
    {
        return 4;
    }
}

Startup.cs (ConfigureServices)

public void ConfigureServices(IServiceCollection services)
{
    services.AddApplicationInsightsTelemetry(Configuration);
    services.AddMvc();

    services.AddTransient<ITestService, TestService>();
}

HomeController.cs

using Microsoft.Extensions.DependencyInjection;

namespace Core.Controllers
{
    public class HomeController : Controller
    {
        public HomeController(IServiceProvider serviceProvider)
        {
            var service = serviceProvider.GetService<ITestService>();
            int rnd = service.GenerateRandom();
        }
BrunoLM
  • 97,872
  • 84
  • 296
  • 452
26

If you just need to resolve one dependency for the purpose of passing it to the constructor of another dependency you are registering, you can do this.

Let's say you had a service that took in a string and an ISomeService.

public class AnotherService : IAnotherService
{
    public AnotherService(ISomeService someService, string serviceUrl)
    {
        ...
    }
}

When you go to register this inside Startup.cs, you'll need to do this:

services.AddScoped<IAnotherService>(ctx => 
      new AnotherService(ctx.GetService<ISomeService>(), "https://someservice.com/")
);
kilkfoe
  • 445
  • 5
  • 11
raterus
  • 1,980
  • 20
  • 23
  • 1
    The OP didn't state the reason for needing to resolve a service in the ConfigureService method, but this is most likely the reason somebody would think to do that – kilkfoe May 10 '19 at 20:44
  • 2
    In fact this should be the accepted answer... Although Henk Mollema's answer is very illustrative, nowadays your answer is cleaner and doesn't introduce problems related on building an intermediate IServiceProvider (different instances of singletons...). Probably, this solution wasn't available in 2015 when Henk anwered, but now it's the way to go. – Vi100 Sep 12 '19 at 10:58
  • Tried this but `ISomeService` was still null for me. – ajbeaven Dec 18 '19 at 11:39
  • 2 questions: 1) If the parameter constructor of service class AnotherService changes (removed or added services), then I need to modify the register segment of service IAnotherService and it keeps changing? 2) Instead, I can add only one constructor for AnotherService with 1 parameter like public AnotherService (IServiceProvider serviceProvider) and get services I need from the constructor. And I just need to register service class AnotherService in Startup class like services.AddTransient(sp => { var service = new AnotherService(sp); return service; }); – Thomas.Benz Jan 11 '20 at 15:01
  • 2
    `services.AddScoped(ctx => ActivatorUtilities.CreateInstance(ctx, "https://someservice.com/") );` should be the preferred solution. – Frode Nilsen Apr 26 '21 at 10:11
  • @FrodeNilsen to clarify further for others, `ActivatorUtilities.CreateInstance` is dynamic in that is uses the service collection to fill in as many ctor args as it can, then uses the additional parameters provided to the method to fill in the rest. this also solves for @Thomas.Benz questions – Michael Rieger Sep 02 '22 at 13:01
20

You can inject dependencies in attributes like AuthorizeAttribute in this way

var someservice = (ISomeService)context.HttpContext.RequestServices.GetService(typeof(ISomeService));

#######

...more succinct way to write the above code by @Code Ranger's comment below:

var someservice = context.HttpContext.RequestServices.GetService<ISomeService>();
Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
Bora Aydın
  • 439
  • 4
  • 6
  • 2
    This is what I was searching for.. Thanks – Reyan Chougle Mar 28 '20 at 07:50
  • Thank you, Bora Aydın. Is there any downside to doing it this way versus constructor injection? – Lukas Sep 04 '20 at 16:04
  • You can use this type of resolving where constructor injection is not available like attributes. As far as I know there is no downside of it. It is just another way of resolving dependencies. – Bora Aydın Sep 12 '20 at 20:20
  • This is they way to go if you are using IHttpContextAccessor as DI mixed with your repository. – revobtz May 03 '21 at 19:42
  • 2
    Really good answer, just to add to this though - A more succinct way to write this is: `var someservice = context.HttpContext.RequestServices.GetService();` – Code Ranger Feb 01 '22 at 21:41
6

I know this is an old question but I'm astonished that a rather obvious and disgusting hack isn't here.

You can exploit the ability to define your own ctor function to grab necessary values out of your services as you define them... obviously this would be ran every time the service was requested unless you explicitly remove/clear and re-add the definition of this service within the first construction of the exploiting ctor.

This method has the advantage of not requiring you to build the service tree, or use it, during the configuration of the service. You are still defining how services will be configured.

public void ConfigureServices(IServiceCollection services)
{
    //Prey this doesn't get GC'd or promote to a static class var
    string? somevalue = null;

    services.AddSingleton<IServiceINeedToUse, ServiceINeedToUse>(scope => {
         //create service you need
         var service = new ServiceINeedToUse(scope.GetService<IDependantService>())
         //get the values you need
         somevalue = somevalue ?? service.MyDirtyHack();
         //return the instance
         return service;
    });
    services.AddTransient<IOtherService, OtherService>(scope => {
         //Explicitly ensuring the ctor function above is called, and also showcasing why this is an anti-pattern.
         scope.GetService<IServiceINeedToUse>();
         //TODO: Clean up both the IServiceINeedToUse and IOtherService configuration here, then somehow rebuild the service tree.
         //Wow!
         return new OtherService(somevalue);
    });
}

The way to fix this pattern would be to give OtherService an explicit dependency on IServiceINeedToUse, rather than either implicitly depending on it or its method's return value... or resolving that dependency explicitly in some other fashion.

Izzy
  • 1,764
  • 1
  • 17
  • 31
4

You can inject dependencies using IApplicationBuilder instance in this way

public void Configure(IApplicationBuilder app)
{
    //---------- Your code

    using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
    {
        var resultLogic = serviceScope.ServiceProvider.GetService<IResultLogic>();
        resultLogic.YourMethod();
    }

    //---------- Your code
}
Petter Hesselberg
  • 5,062
  • 2
  • 24
  • 42
Bibin Gangadharan
  • 1,393
  • 12
  • 13
-1
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ISelfServiceConfigLoad, SelfServiceConfigLoader>();
    var sp = services.BuildServiceProvider();
    var configservice = sp.GetServices<ISelfServiceConfigLoad>();
    services.AddSingleton<IExtractor, ConfigExtractor>( sp =>
    {
        var con = sp.GetRequiredService<ISelfServiceConfigLoad>();
        var config = con.Load();
        return new ConfigExtractor(config.Result);
    });
    services.AddSingleton<IProcessor<EventMessage>, SelfServiceProcessor>();          
    services.AddTransient<ISolrPush, SolrDataPush>();
    services.AddSingleton<IAPICaller<string, string>, ApiRestCaller<string, string>>();
    services.AddSingleton<IDataRetriever<SelfServiceApiRequest, IDictionary<string, object>>, SelfServiceDataRetriever>();
}
Petter Hesselberg
  • 5,062
  • 2
  • 24
  • 42
  • 2
    How does that answer the question? Please provide some explaining text. – Matt Nov 19 '21 at 09:06
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 19 '21 at 09:20
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/30382243) – Andrew Halil Nov 20 '21 at 05:17
  • In the code snippet you gave you're **registering** services. But the question was, how to **get an instance** of any service inside of ConfigureServices? – Matt Nov 22 '21 at 08:35
  • He get the instance using the AddSingleton overload which gives access to serviceProvider. Instead of calling IServiceCollection.BuildServiceProvider() https://stackoverflow.com/q/31863981/423356 calling BuildServiceProvider() in ConfigureServices seems not best practice – kite Feb 01 '22 at 22:46
-6
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddDbContext<ConfigurationRepository>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("SqlConnectionString")));

    services.AddScoped<IConfigurationBL, ConfigurationBL>();
    services.AddScoped<IConfigurationRepository, ConfigurationRepository>();
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Nathan Alard
  • 1,753
  • 17
  • 9
  • 5
    Your answers are more likely to get accepted and upvoted if you provide a brief explanation of *why* it is a good answer, not just a code snippet. It also helps the asker to be sure this is actually answering the question they asked. – Jim L Feb 14 '18 at 18:47
  • 1
    Somebody incorrectly flagged your answer as low-quality. You should add some accompanying text to explain how your answer works to prevent further flagging and/or downvotes. A code-only answer [is not low-quality](https://meta.stackoverflow.com/a/358757/1364007). Does it attempt to answer the question? If not, flag as 'not an answer' or recommend deletion (if in the review queue). b) Is it technically incorrect? Downvote or comment. [From review](https://stackoverflow.com/review/low-quality-posts/18823309). – Wai Ha Lee Feb 14 '18 at 21:54