Dependency Injection
Introduction to Dependency Injection
Dependency Injection (DI) is a design pattern used to implement Inversion of Control (IoC) between classes and their dependencies. It allows for better modularity and testability by injecting dependencies rather than creating them within the classes.
Why Use Dependency Injection?
- Decoupling: Reduces the dependency of one class on another.
- Testability: Makes it easier to test individual components.
- Maintainability: Simplifies code maintenance and updates.
Setting Up Dependency Injection in .NET
In .NET, DI is supported out of the box and can be configured in the Startup.cs
file.
Step 1: Define Interfaces and Implementations
Example: Defining Interfaces and Implementations
public interface IMessageService {
void SendMessage(string message);
}
public class EmailService : IMessageService {
public void SendMessage(string message) {
Console.WriteLine($"Email sent: {message}");
}
}
public class SmsService : IMessageService {
public void SendMessage(string message) {
Console.WriteLine($"SMS sent: {message}");
}
}
Step 2: Configure Services in Startup.cs
Example: Configuring Services in Startup.cs
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.AddTransient();
// services.AddTransient(); // Uncomment to use SmsService
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
// Middleware configuration
}
}
Step 3: Inject Dependencies in Controllers
Example: Injecting Dependencies in Controllers
public class HomeController : Controller {
private readonly IMessageService _messageService;
public HomeController(IMessageService messageService) {
_messageService = messageService;
}
public IActionResult Index() {
_messageService.SendMessage("Welcome to Dependency Injection in .NET!");
return View();
}
}
Lifetime of Services
In .NET DI, services can have different lifetimes:
- Transient: Created each time they are requested.
- Scoped: Created once per request.
- Singleton: Created the first time they are requested and used for the lifetime of the application.
Example: Configuring Service Lifetimes
Example: Configuring Service Lifetimes
public void ConfigureServices(IServiceCollection services) {
services.AddTransient(); // Transient
services.AddScoped(); // Scoped
services.AddSingleton(); // Singleton
}
Advanced Dependency Injection
For more complex scenarios, you can use advanced DI techniques such as:
- Named Instances: Using named services for different implementations.
- Factory Methods: Using factories to create service instances.
- Decorator Pattern: Adding behavior to services.
Example: Using Factory Methods
Example: Using Factory Methods
public void ConfigureServices(IServiceCollection services) {
services.AddTransient(provider => {
var useEmail = bool.Parse(Configuration["UseEmail"]);
if (useEmail) {
return new EmailService();
} else {
return new SmsService();
}
});
}
Conclusion
Dependency Injection is a powerful pattern that enhances the modularity, testability, and maintainability of your applications. By understanding and implementing DI in .NET, you can create more flexible and robust applications.