What is Dependency Injection (DI)?
Dependency Injection (DI) is a design pattern used to achieve loose coupling between classes and their dependencies.
Instead of a class creating its own dependencies, they are injected from the outside, usually by a framework like .NET Core. This promotes better maintainability, testability, and modularity in application design.
Why Use DI?
Improves testability (easily mock dependencies)
Enhances flexibility and maintainability
Supports SOLID principles, especially:
- Inversion of Control (IoC)
- Single Responsibility Principle
How DI Works in .NET Core?
.NET Core comes with a built-in IoC container that supports three main service lifetimes:
Lifetime |
Description |
Example Use Case |
Singleton |
One instance for the entire application |
Caching, config, loggers |
Scoped |
One instance per HTTP request |
User/session-level services |
Transient |
New instance every time it's requested |
Lightweight, stateless logic |
Step-by-Step Example: Injecting a Service
1. Define an Interface
public interface IMessageService
{
string GetMessage();
}
2. Create a Concrete Implementation
public class HelloMessageService : IMessageService
{
public string GetMessage()
{
return "Hello from DI!";
}
}
3. Register the Service in the Program.cs (.NET 6+)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IMessageService, HelloMessageService>(); // DI registration
4. Inject the Service in a Controller
[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
private readonly IMessageService _messageService;
public HomeController(IMessageService messageService)
{
_messageService = messageService;
}
[HttpGet]
public string Get() => _messageService.GetMessage();
}
Output
GET /home
=> "Hello from DI!"
Real-World Use Case
In a recent project, we used DI to inject:
- ILoggingService
- IEmailService
- IUserRepository
This allowed us to easily swap implementations during unit testing and to mock external services such as SendGrid and SQL Server, enabling a much more testable and scalable architecture.
Summary
- DI is built into .NET Core via IServiceCollection.
- Encourages clean, testable, and modular code.
- Supports different service lifetimes (Singleton, Scoped, Transient).
- Use constructor injection as the standard approach.