QUICK START:HTMLCSSJavaScriptTypeScriptPythonSQLReactNext.jsNode.jsLinux & UbuntuKotlinSwiftC# / .NETJavaGoRustC++DSASystem DesignDevOpsCybersecurityAI / ML
Intermediate 22 min readModule: Module 6: Dependency Injection & Configuration Architecture in .NET

Dependency Injection, Service Lifetimes & Options Pattern

Build maintainable, testable software using .NET's built-in Dependency Injection container (IServiceCollection), service lifetimes (Transient, Scoped, Singleton), and strongly typed Options.

What You Will Learn in This Lesson

  • The Inversion of Control (IoC) principle and Dependency Injection in .NET
  • Service Lifetimes: `Transient` (every request), `Scoped` (per HTTP request), `Singleton` (application lifetime)
  • The Captive Dependency anti-pattern and how to avoid it
  • Strongly typed application configuration with `IOptions<T>` and `IOptionsSnapshot<T>`

Introduction & Core Concept

Modern .NET includes a high-performance, built-in Dependency Injection (DI) container at the heart of the framework. Every component in ASP.NET Core—controllers, middleware, database contexts, loggers, and background services—is registered in the DI container and resolved via constructor injection.
WHY DOES THIS MATTER IN THE REAL WORLD?

Hardcoding dependencies with 'new Service()' creates tightly coupled systems that cannot be unit-tested. Dependency Injection decouples implementations from interfaces, enabling modular architecture and seamless mocking.

Syntax & Structure

csharp
builder.Services.AddScoped<IUserRepository, SqlUserRepository>();
builder.Services.Configure<DatabaseOptions>(builder.Configuration.GetSection("Database"));

Configuring DI Container and Constructor Injection in .NET

csharp
csharp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// Dependency Injection and Options Pattern in .NET 9
using System;
// 1. Strongly-typed configuration options
public class PaymentGatewayOptions
{
public string ApiKey { get; set; } = "sk_live_default_key";
public int TimeoutSeconds { get; set; } = 30;
}
// 2. Service interface and implementation
public interface IPaymentService
{
void ProcessPayment(decimal amount);
}
public class StripePaymentService : IPaymentService
{
private readonly PaymentGatewayOptions _options;
// Constructor Injection of options
public StripePaymentService(PaymentGatewayOptions options)
{
_options = options;
}
public void ProcessPayment(decimal amount)
{
Console.WriteLine($"[Stripe] Processed payment of USD {amount:N2} using API Key ending in '...{_options.ApiKey[^4..]}'");
}
}
// 3. Controller consuming injected service
public class CheckoutController
{
private readonly IPaymentService _paymentService;
public CheckoutController(IPaymentService paymentService)
{
_paymentService = paymentService;
}
public void ExecuteCheckout(decimal cartTotal)
{
Console.WriteLine("Executing checkout transaction...");
_paymentService.ProcessPayment(cartTotal);
}
}
public class Program
{
public static void Main()
{
// Demonstration of resolving configured dependency hierarchy
var config = new PaymentGatewayOptions { ApiKey = "sk_live_kwas_academy_secret_9981" };
IPaymentService paymentService = new StripePaymentService(config);
var controller = new CheckoutController(paymentService);
controller.ExecuteCheckout(249.99m);
}
}

Line-by-Line Technical Breakdown

1The Captive Dependency Anti-Pattern: A Captive Dependency occurs when a service with a longer lifetime captures a service with a shorter lifetime (e.g., a `Singleton` service injecting a `Scoped` DbContext). The scoped DbContext is kept alive for the lifetime of the application, causing concurrency exceptions and memory leaks.

Try It Yourself (Interactive Editor)

Modify the code in real-time and click Run to test live browser output and console logs.

Intelligent Code Runner & Live Sandbox[CSHARP]
CSHARP SOURCE EDITOR
Interactive Live Code

Common Mistakes & How to Avoid Them

#1: Registering Entity Framework DbContext as a Singleton service.

DbContext is not thread-safe. Registering it as a Singleton causes multiple concurrent HTTP requests to share the same database connection, causing fatal runtime concurrency crashes.

Incorrect / Antipattern
builder.Services.AddSingleton<AppDbContext>();
Correct / Professional Solution
builder.Services.AddDbContext<AppDbContext>(); // Defaults to Scoped

Industry Best Practices & Professional Standards

  • Register DbContexts and unit-of-work repositories as `Scoped` services.
  • Register lightweight, stateless utility services as `Transient`.
  • Register thread-safe caches and telemetry clients as `Singleton`.

Lesson Summary & Core Takeaways

  • .NET features a built-in IoC container managing service lifetimes.
  • `Transient`, `Scoped`, and `Singleton` control instance allocation.
  • The Options pattern binds `appsettings.json` sections to strongly typed classes.