Overview of dependency injection
Dependency injection is a best-practice software development technique for ensuring classes remain loosely coupled and making unit testing easier.
Take, for example, a service that uses a 3rd party service for sending emails. Traditionally, any class needing to use this service might create an instance.
public interface IEmailService
{
void Send(string from, string to, string subject, string body);
}
public class NewsletterService
{
private readonly IEmailService EmailService;
public NewsletterService()
{
EmailService = new SendGridEmailService();
}
public void SignUp(string emailAddress)
{
EmailService.Send("noreply@sender.com", emailAddress, "Subject", "Body");
}
}
The problem with this approach is that it tightly couples the classes NewsletterService and SendGridEmailService.
When unit testing NewsletterService.SignUp, the method being tested would actually try to send an email.
Not only is this not so good for your inbox, it's not good for costs (if your provider charges per email),
and gives more points at which your test can fail when in fact all we need to know is that the SignUp method attempts
to send out emails to welcome new users to our service.
Using dependency injection instead of every consuming class having to create an instance of the correct IEmailService implementor,
our consuming classes expect the correct instance to be supplied when it is created.
public class NewsletterService
{
private readonly IEmailService EmailService;
public NewsletterService(IEmailService emailService)
{
EmailService = emailService;
}
public void SignUp(string emailAddress)
{
EmailService.Send(...);
}
}
A Dependency Injection Framework (such as the one used by default in ASP.NET Core and Blazor applications) will automatically
inject an instance of the correct class when we ask it to build up an instance of NewsletterService for us.
Not only does this decouple our classes by making NewsletterService unaware of the class that implements IEmailService,
but it also makes unit-testing very simple. For example, using the Moq framework.
[Fact]
public void WhenSigningUp_ThenSendsAnEmail()
{
var mockEmailService = new Mock<IEmailService>();
var subject = new NewsletterService(mockEmailService.Object);
subject.SignUp("Bob@Monkhouse.com");
mockEmailService
.Verify(
x => x.Send("noreply@sender.com", "Bob@Monkhouse.com", "Subject", "Body"),
Times.Once);
}
Now that we understand the basic pattern of dependency injection, we can look at how to apply it specifically in Blazor applications. In the next section we will look at injecting dependencies into Blazor components. After that we will explore dependency lifetimes and scopes to understand how long our injected objects live and how many consumers share the same instance.