๐งฉ What is Dependency Injection (DI)?
Dependency Injection (DI) is a design pattern used to achieve loose coupling between classes and their dependencies.
In simple terms:
Instead of a class creating its own dependencies, they are provided (injected) from the outside — typically by a framework or container.
๐ง Example Without DI (Tight Coupling)
Here:
- NotificationService directly depends on EmailService.
- If we want to replace EmailService with, say, SmsService, we must change the code inside NotificationService.
✅ Example With DI (Loose Coupling)
Now you can plug in any implementation (Email, SMS, Push) without changing NotificationService.
๐งฑ Dependency Injection in .NET Core
.NET Core has built-in support for Dependency Injection via the Microsoft.Extensions.DependencyInjection namespace.
You configure DI inside the Program.cs or Startup.cs (depending on .NET version).
๐งฐ Typical .NET Core DI Setup
Example — in Program.cs (.NET 6/7/8 minimal hosting model)
var builder = WebApplication.CreateBuilder(args);
๐ How DI Works in .NET Core
When you run the app:
-
The service container is created by
WebApplication.CreateBuilder. -
Services are registered using
builder.Services.Add...(). -
When a class (e.g., controller, page, or middleware) requests a dependency, the DI container creates and injects it automatically.
๐ Service Lifetimes
| Lifetime | Description | Use Case |
|---|---|---|
| Transient | New instance created every time it’s requested | Lightweight, stateless services |
| Scoped | One instance per request (HTTP scope) | Web request-specific services |
| Singleton | Single instance for the entire app lifetime | Configuration, caching, logging |
Example:
๐ง DI Example in ASP.NET Core Controller
✅ ASP.NET Core automatically injects CustomerService because it was registered in the DI container.
⚙️ Advanced DI Topics
1️⃣ Constructor Injection (most common)
Dependencies passed via constructor.
2️⃣ Method Injection
Dependencies passed as method parameters.
3️⃣ Property Injection
Dependency assigned via property (not common in .NET Core DI by default).
๐ฉ Built-in DI Container Features
- Open Generics Support
builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); - Service Replacement: Simply remove MyService registration with IMyService and add new registration MyMockService with IMyService.
This is useful when you are using some library and that has registered IMyService with MyService, so now Replace statement will replace all previous registration with new one.
builder.Services.AddSingleton<IMyService, MyService>();
builder.Services.Replace(ServiceDescriptor.Singleton<IMyService, MyMockService>()); - Configuration + Options Pattern
builder.Services.Configure<MyConfig>(builder.Configuration.GetSection("MySection"));
๐งฐ DI in Non-Web .NET Apps
You can also use DI in:
- Console apps
- Worker services
- Background jobs
Example:
๐ก Benefits of Using DI
| Benefit | Description |
|---|---|
| Loose Coupling | Easier to swap implementations |
| Testability | Use mocks in unit tests easily |
| Reusability | Services can be reused across components |
| Maintainability | Reduces hard-coded dependencies |
| Scalability | Centralized lifecycle management |
⚠️ Common Pitfalls
| Mistake | Impact |
|---|---|
| Registering service with wrong lifetime | Memory leaks or inconsistent behavior |
| Creating new instances manually inside service | Breaks DI chain |
| Overusing Singleton | Can cause thread-safety issues |
| Circular dependencies | Two services depend on each other — runtime error |
๐งพ Summary
| Aspect | Details |
|---|---|
| Pattern | Dependency Injection (DI) |
| Built-in Container | Microsoft.Extensions.DependencyInjection |
| Registration Methods | AddSingleton, AddScoped, AddTransient |
| Goal | Loose coupling, better testability, and flexibility |
| Injection Methods | Constructor (primary), Method, Property |
| Used In | ASP.NET Core, Worker Services, Blazor, Console Apps |
No comments:
Post a Comment