According to the docs we can inject the following services into the startup class:
But we can also use method injection to resolve these services in the Configure()
method:
Additional services, such as IWebHostEnvironment, ILoggerFactory, or anything defined in ConfigureServices, can be specified in the Configure method signature. These services are injected if they're available.
Does it make a difference which injection variant I use?
To be specific, is there a difference resolving the IWebHostEnvironment
in the constructor and then access it in the Configure()
method via private field vs. injecting it as a method parameter?
public class Startup
{
private readonly IWebHostEnvironment env;
public Startup(IWebHostEnvironment env)
{
this.env = env;
}
public void Configure(IApplicationBuilder app)
{
if (this.env.IsDevelopment())
[...]
}
}
vs.
public class Startup
{
public Startup() {}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
[...]
}
}
Generally speaking, constructor & method DI can be a preference or a requirement based on some framework that uses this but not the other. In asp.net core
(as well as .net core
generally), it's recommended to use constructor injection because it states clearly the dependencies. That makes more sense than method injection. However in some cases you have to use method injection because the dependencies can only be available at the time of invoking the method or at least not available at the time of constructing the classes/services. Sometimes the injected services are used only for a specific method call, in such cases method injection will be used. In some cases, the service instance is singleton but its method call requires some scoped services so method injection will be used instead. One example for that scenario is when using convention-based middleware
. Convention-based middlewares are singleton, created once at the app startup, not for each request. So all scoped services must be injected into the Invoke
or InvokeAsync
method. Factory-based middlewares however can have its scoped services injected into the constructor because they can be created per request (registered as scoped or transient).
As in the case of Startup
class. You can inject some built-in services into the Startup
s constructor such as IConfiguration
, IWebHostEnvironment
, ... Usually many services available (registered before) before ConfigureServices
can be injected into Startup
's constructor. That means all services registered in ConfigureServices
are NOT available for injection into the Startup
's constructor. You can however inject all registered services (including built-in ones and yours) into the method Configure
. Note that the services injected into Configure
should be singleton & transient, for scoped services there may be issues when using them. That really depends on the specific services you use.
Here is an example showing that injecting a service of your own (registered in ConfigureServices
) cannot be done into the Startup
's constructor:
public interface ISomeService {}
public class SomeService : ISomeService {}
public class Startup {
//will not work because at this time, the ISomeService has not been registered yet
public Startup(ISomeService someService){
//an error will be thrown complaining about not being able to
//resolve the ISomeService
}
public void ConfigureServices(IServiceCollection services){
//...
services.AddSingleton<ISomeService,SomeService>();
//...
}
//this works because at this time the ConfigureServices was called
//the services container has been built with your registered ISomeService
public void Configure(IApplicationBuilder app, ISomeService someService){
//...
}
}