Dependency Injection
Prerequisites: Reflection & attributes
Rather than a class constructing its own dependencies directly, they are provided ("injected") from outside — usually through the constructor — making the class easier to test and reconfigure.
interface IEmailSender {
void Send(string to, string message);
}
class OrderService {
private readonly IEmailSender _emailSender;
public OrderService(IEmailSender emailSender) {
_emailSender = emailSender; // injected, not created here
}
public void PlaceOrder(string customerEmail) {
_emailSender.Send(customerEmail, "Order confirmed!");
}
}
ASP.NET Core has a built-in DI container — registering
IEmailSender once (builder.Services.AddScoped<IEmailSender, SmtpEmailSender>();) means every controller that asks for an
IEmailSender in its constructor gets one automatically, with no
manual wiring at each call site.
Common mistakes
- A class calling
new SmtpEmailSender()directly instead of depending on theIEmailSenderinterface — this makes it impossible to substitute a test double (a mock) in a unit test.