DI in .Net Core

Transient

Transient objects are always different; a new instance is provided to every controller and every service.

1
2
3
4
5
services.AddTransient<IOssIndexRepository, OssIndexRepository>();

// with parameters
var projectRepository = new ProjectRepository(connectionString);
services.AddTransient<IProjectRepository>(s => projectRepository);

Scoped

Scoped objects are the same within a request, but different across different requests.

1
services.AddScoped<IOperationScoped, Operation>();

Singleton

Singleton objects are the same for every object and every request.

1
2
var ossIndexRepository = new OssIndexRepository(connectionString);
services.AddSingleton<IOssIndexRepository>(ossIndexRepository);

AddOptions

If you need to resolve a dependency inside ConfigureServices you may be tempted to to call BuildServiceProvider, although this will work you will then create an additional copy of singleton service which is bad.

I’ve run into this kind of issue when I needed to inject a Scoped dependancy into another dependancy which was a Singleton dependancy.

Example of the wrong way to do it

1
2
3
4
5
6
7
8
9
10
11
12
13
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient(IMyScopedService, MyScopedService);

using (var serviceProvider = services.BuildServiceProvider())
{
var myScopedService = serviceProvider.GetRequiredService<IMyScopedService>();
services.AddSweetSingleton(options =>
{
options.SomethingFromScopedService = myScopedService.SomethingHelpfulFromScopedService();
})
}
}

Microsoft suggest to avoid calls to BuildServiceProvider in ConfigureServices!

The best way to do this is to create an Options object

Example of the correct way

1
2
3
4
5
6
7
8
9
10
11
12
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient(IMyScopedService, MyScopedService);
services.AddTransient(IMySingletonService, MySingletonService);

services
.AddOptions<MySingletonServiceOptions>()
.Configure<IMyScopedService>((options, service) =>
{
options.SomethingFromScopedService = service.SomethingHelpfulFromScopedService();
});
}

References