Dependency Injection Lifetimes in .NET 8 with Use Cases
.NET 8 provides a robust Dependency Injection (DI) system. Understanding the three main lifetimes—Singleton, Scoped, and Transient—is essential for writing clean, maintainable, and scalable applications.
1. Singleton
Lifetime: One instance for the entire application.
Use Case: Ideal for logging, configuration, or caching services that should be shared globally.
builder.Services.AddSingleton<IMyService, MyService>();
Example:
public interface IMyService
{
Guid GetOperationId();
}
public class MyService : IMyService
{
private readonly Guid _id = Guid.NewGuid();
public Guid GetOperationId() => _id;
}
Behavior: The same instance is returned every time it's requested.
2. Scoped
Lifetime: One instance per HTTP request.
Use Case: Best for per-request logic, such as working with Entity Framework DbContext
.
builder.Services.AddScoped<IUserService, UserService>();
Example:
public interface IUserService
{
string GetCurrentUser();
}
public class UserService : IUserService
{
public string GetCurrentUser() => "user@example.com";
}
Behavior: A new instance is created per request, shared within that request.
3. Transient
Lifetime: A new instance every time it's injected.
Use Case: Perfect for lightweight, stateless services like validators or formatters.
builder.Services.AddTransient<IFormatterService, FormatterService>();
Example:
public interface IFormatterService
{
string Format(string input);
}
public class FormatterService : IFormatterService
{
public string Format(string input) => input.ToUpperInvariant();
}
Behavior: A completely new instance is provided on every call.
Comparison Table of DI Lifetimes
Lifetime | Created Per | Reused | Best For |
---|---|---|---|
Singleton | Application | Yes | Logging, Configuration, Caching |
Scoped | HTTP Request | Yes (per request) | DbContext, User-specific logic |
Transient | Every Use | No | Formatters, Validators, Stateless Services |
Best Practices for DI in .NET 8
- Use Singleton only for services that are stateless and thread-safe.
- Scoped is great for services that manage request-based state like database access.
- Use Transient when the service is lightweight and short-lived.
Registering DbContext
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
Conclusion
In .NET 8, understanding DI lifetimes is key to building scalable and efficient apps. Choose wisely between Singleton, Scoped, and Transient based on the service behavior and intended usage.
If you found this guide helpful, share it with your developer friends or bookmark it for later!
0 Comments