0 0
Read Time:2 Minute, 44 Second

🧠 What Are Service Lifetimes?

In .NET Core, services registered in the Dependency Injection (DI) container can be configured with different lifetimes, which define how and when service instances are created and disposed.

The three built-in lifetimes are:

  • Singleton

  • Scoped

  • Transient

Choosing the right lifetime is critical for application performance, scalability, and correctness.


🔌 Real-Time Example: Email Notification System

Let’s assume you’re building an email notification system for an e-commerce website. This system includes:

  • A logging service to log every sent email.

  • A notification service that handles email delivery.

  • A repository that logs messages to a database.

Here’s how different lifetimes fit in:

Service Description Lifetime
LoggerService Global logger shared across all users Singleton
NotificationService Needs user-specific configurations Scoped
EmailFormatterService Lightweight, stateless string formatting Transient

🟢 1. Singleton

🧾 Description:

Created once and shared across the entire application lifetime.

🧪 Example:

services.AddSingleton<ILoggerService, LoggerService>();

💡 Real Use Case:

A LoggerService that writes logs to a file or external system like ELK or App Insights.

All users and requests share the same logger instance.


🔵 2. Scoped

🧾 Description:

Created once per HTTP request. Same instance is reused throughout the request.

🧪 Example:

services.AddScoped<INotificationService, EmailNotificationService>();

💡 Real Use Case:

A NotificationService that uses HttpContext to determine user-specific configurations like email templates.

Perfect for services involving user data or request context.


🟣 3. Transient

🧾 Description:

A new instance is created every time it’s requested.

🧪 Example:

services.AddTransient<IEmailFormatterService, EmailFormatterService>();

💡 Real Use Case:

EmailFormatterService that adds dynamic signatures or greeting lines. It’s stateless and lightweight.

Transient services are ideal for utility functions or non-shared tasks.


🖼️ Visual Diagram – .NET Core Service Lifetimes


⚠️ Warning: Mixing Lifetimes Improperly

You should NOT inject a Scoped or Transient service into a Singleton. It may lead to unexpected behavior or runtime exceptions.

✅ Workaround:

Use IServiceProvider or a factory method inside the singleton:

public class SafeSingleton
{
private readonly IServiceProvider _serviceProvider;
public SafeSingleton(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}

public void DoSomething()
{
var scopedService = _serviceProvider.GetRequiredService<IMyScopedService>();
}
}


🗂️ Summary Table

Lifetime Instance Created Scope Best Use Cases
Singleton Once for app lifetime Global Caching, logging, config reader
Scoped Once per request Per user Business logic, DB context, user service
Transient Every time Per usage Utilities, helpers, formatters

💬 Interview Follow-Up Questions & Answers

❓ Q1: What happens if you inject a Scoped service into a Singleton?

🅰️ This causes a runtime error because Scoped services are tied to the request context. The singleton outlives the request scope.


❓ Q2: Can I inject Transient into Scoped or Singleton?

🅰️ Yes. But be cautious with Singletons because any stateful behavior in the Transient service may lead to unexpected side effects.


❓ Q3: Which service lifetime should I use for EF Core DbContext?

🅰️ Scoped. EF Core DbContext is not thread-safe and must be scoped per request.


❓ Q4: What’s the default lifetime in .NET Core?

🅰️ There is no default. You must specify it explicitly: AddSingleton, AddScoped, or AddTransient.


❓ Q5: How does lifetime impact performance?

🅰️ Singleton reduces object creation overhead, while Transient increases it. However, Singleton can be risky if shared state is not managed carefully.


📌 Final Thoughts

Service lifetimes are fundamental in building scalable, testable, and maintainable applications in .NET Core. Start with Scoped for most services, Singleton for global state, and Transient for lightweight, disposable logic.

Previous post Understanding Dependency Injection and IoC in .NET Core – A Beginner-Friendly Guide with Real-World Examples
Next post 30 Algorithm Challenges in C# (With Real-World Examples & Code)
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Close
0
Would love your thoughts, please comment.x
()
x
× How can I help you?