Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
What is the AddSingleton vs AddScoped vs Add Transient C# Asp.net Core?
Dependency injection in ASP.NET Core provides three service lifetime options that determine when service instances are created and disposed. These service lifetimes − AddSingleton, AddScoped, and AddTransient − control the lifecycle of your registered services.
Understanding these lifetimes is crucial for proper memory management and ensuring your application behaves correctly across different requests and users.
Syntax
All three methods follow the same registration syntax in the ConfigureServices method −
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton<IInterface, Implementation>();
services.AddScoped<IInterface, Implementation>();
services.AddTransient<IInterface, Implementation>();
}
AddSingleton
When you register a service as Singleton, only one instance exists throughout the entire application lifetime. This single instance is shared across all requests and users.
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton<ILog, Logger>();
}
Example
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
public interface ICounterService {
int GetNextNumber();
}
public class CounterService : ICounterService {
private int _counter = 0;
public int GetNextNumber() {
return ++_counter;
}
}
public class Program {
public static void Main(string[] args) {
var services = new ServiceCollection();
services.AddSingleton<ICounterService, CounterService>();
var serviceProvider = services.BuildServiceProvider();
// Simulate multiple requests
var service1 = serviceProvider.GetService<ICounterService>();
var service2 = serviceProvider.GetService<ICounterService>();
Console.WriteLine($"Service1: {service1.GetNextNumber()}");
Console.WriteLine($"Service2: {service2.GetNextNumber()}");
Console.WriteLine($"Same instance: {object.ReferenceEquals(service1, service2)}");
}
}
The output of the above code is −
Service1: 1 Service2: 2 Same instance: True
AddScoped
When you register a service as Scoped, one instance is created per request. Each HTTP request gets its own instance, but within that request, the same instance is reused.
public void ConfigureServices(IServiceCollection services) {
services.AddScoped<ILog, Logger>();
}
Example
using Microsoft.Extensions.DependencyInjection;
using System;
public interface IRequestService {
string GetRequestId();
}
public class RequestService : IRequestService {
private readonly string _requestId;
public RequestService() {
_requestId = Guid.NewGuid().ToString("N")[..8];
}
public string GetRequestId() {
return _requestId;
}
}
public class Program {
public static void Main(string[] args) {
var services = new ServiceCollection();
services.AddScoped<IRequestService, RequestService>();
var serviceProvider = services.BuildServiceProvider();
// Simulate first request scope
using (var scope1 = serviceProvider.CreateScope()) {
var service1a = scope1.ServiceProvider.GetService<IRequestService>();
var service1b = scope1.ServiceProvider.GetService<IRequestService>();
Console.WriteLine($"Scope1 - Service1a: {service1a.GetRequestId()}");
Console.WriteLine($"Scope1 - Service1b: {service1b.GetRequestId()}");
Console.WriteLine($"Same in scope1: {service1a.GetRequestId() == service1b.GetRequestId()}");
}
// Simulate second request scope
using (var scope2 = serviceProvider.CreateScope()) {
var service2 = scope2.ServiceProvider.GetService<IRequestService>();
Console.WriteLine($"Scope2 - Service2: {service2.GetRequestId()}");
}
}
}
The output of the above code is −
Scope1 - Service1a: a1b2c3d4 Scope1 - Service1b: a1b2c3d4 Same in scope1: True Scope2 - Service2: e5f6g7h8
AddTransient
When you register a service as Transient, a new instance is created every time the service is requested, even within the same request.
public void ConfigureServices(IServiceCollection services) {
services.AddTransient<ILog, Logger>();
}
Example
using Microsoft.Extensions.DependencyInjection;
using System;
public interface ITransientService {
string GetInstanceId();
}
public class TransientService : ITransientService {
private readonly string _instanceId;
public TransientService() {
_instanceId = Guid.NewGuid().ToString("N")[..8];
}
public string GetInstanceId() {
return _instanceId;
}
}
public class Program {
public static void Main(string[] args) {
var services = new ServiceCollection();
services.AddTransient<ITransientService, TransientService>();
var serviceProvider = services.BuildServiceProvider();
var service1 = serviceProvider.GetService<ITransientService>();
var service2 = serviceProvider.GetService<ITransientService>();
var service3 = serviceProvider.GetService<ITransientService>();
Console.WriteLine($"Service1: {service1.GetInstanceId()}");
Console.WriteLine($"Service2: {service2.GetInstanceId()}");
Console.WriteLine($"Service3: {service3.GetInstanceId()}");
Console.WriteLine($"All different: {service1.GetInstanceId() != service2.GetInstanceId()}");
}
}
The output of the above code is −
Service1: x1y2z3w4 Service2: a5b6c7d8 Service3: m9n0p1q2 All different: True
Comparison
| Lifetime | Instance Creation | Disposal | Best Used For |
|---|---|---|---|
| Singleton | Same instance for entire application | Application shutdown | Stateless services, configuration, caching |
| Scoped | One instance per request | End of request | Database contexts, user-specific data |
| Transient | New instance every time requested | Immediately after use | Lightweight, stateless operations |
Conclusion
Choose AddSingleton for services that maintain state across the application, AddScoped for services that should be consistent within a request, and AddTransient for lightweight services that don't hold state. Understanding these lifetimes ensures proper memory management and application behavior.
