patterncsharpCritical
Resolving instances with ASP.NET Core DI from within ConfigureServices
Viewed 0 times
netconfigureservicesaspwithinstancesfromresolvingcorewithin
Problem
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:
But how can I resolve
There are no such methods in
Setting up the container is easy enough:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient();
}But how can I resolve
ISomeService without performing injection? For example, I want to do this:ISomeService service = services.Resolve();There are no such methods in
IServiceCollection.Solution
The
There are also several convenience extension methods available, such as
Resolving services inside the startup class
Injecting dependencies
The runtime's hosting service provider can inject certain services into the constructor of the
The
Any services registered in
Manually resolving dependencies
If you need to manually resolve services, you should preferably use the
It is possible to pass and directly use an
If you must resolve services in the
Please note:
Generally you should avoid resolving services inside the
Or use an overload for
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.
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() (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();
}
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();
}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();
}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();
// Build the intermediate service provider
var sp = services.BuildServiceProvider();
// This will succeed.
var fooService = sp.GetService();
// This will fail (return null), as IBarService hasn't been registered yet.
var barService = sp.GetService();
}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 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(sp =>
{
var fooService = sp.GetRequiredService();
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.
Code Snippets
var service = (IFooService)serviceProvider.GetService(typeof(IFooService));public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
// Use Configuration here
}public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IFooService>();
}
public void Configure(IApplicationBuilder app, IFooService fooService)
{
fooService.Bar();
}public void Configure(IApplicationBuilder app)
{
var serviceProvider = app.ApplicationServices;
var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}public Startup(IServiceProvider serviceProvider)
{
var hostingEnv = serviceProvider.GetService<IWebHostEnvironment>();
}Context
Stack Overflow Q#32459670, score: 941
Revisions (0)
No revisions yet.