In this blog, we are going to learn about Dependency Injection. And, how we can implement Dependency Injection in C#? We will also learn the ways we can implement Dependency Injection in C#.
What is Dependency Injection (DI)?
So, let’s first define the Dependency Injection. Dependency Injection is a design approach, which helps programmer to create loosely coupled code. In another way, we can say that Dependency Injection is used to remove dependency between two classes and helps to create independent classes.
So, If we pass an object from the container, then it will automatically supply the dependencies of that container. This design pattern allows us to implement the dependency and no need to create an object manually. This avoids tight coupling and gives us better control over the code structure.
Tight Coupling – A bad coding practice
Tight coupling is a bad coding practice in any programming language. In tight coupling, a class is highly dependent on another class. We can overcome this problem by implementing Dependency Injection in C#. But, before implementing Dependency Injection (DI), let’s see the problem that could occur in a traditional coding style.
Firstly, let’s look at the below code snippet:
class Notifications
{
void Notify()
{
Messages objMessages = new Messages();
objMessages.SendSMS();
objMessages.SendEmail();
}
}
class Messages
{
public void SendSMS()
{
Console.WriteLine("Send SMS to Users");
}
public void SendEmail()
{
Console.WriteLine("Send Email Notifications to Users");
}
}
Here, we have two classes Notifications
and Messages
. Class
is highly dependent on Notifications
class, this is because we are creating an object of Messages
class inside Messages
Notify()
method of Notifications
class. So, in this way, this code style shows tight coupling. And, this is not a good coding practice. We can solve this by implementing Dependency Injection.
What is Inversion of Control?
Inversion of Control (IoC) is a generic coding style of a software application that helps in creating reusable, loosely coupled classes that are easy to maintain.
Inversion of Control (IoC) states that changes in lower modules should not affect the higher level of a module. IoC enables loose coupling for better software design and easy testing of software components.
Relation between Inversion of Control and Dependency Injection
Inversion of Control (IOC) and Dependency Injection (DI) are used interchangeably. DI is the way to achieve IoC. Also, DI is not the only way to achieve IOC.
What are the benefits of using Dependency Injection in C#?
Creating loosely coupled classes/ components is one of the major advantages of using Dependency Injection.
By looking at the above definition of Dependency Injection, it is absolutely clear that Dependency Injection is used to create independent classes. DI enables us to make our code maintainable, it also reduces future complexities and dependencies in classes.
So, Dependency Injection in C# enables the following benefits to our software applications:
- More decoupled components and less tight coupling
- Make our code maintainable
- Enables clean code practice
How to Implement Dependency Injection in C#?
In this article, we will learn 3 different ways to implement Dependency Injection in C# application:
- Constructor Injection
- Property Injection
- Method Injection
Let’s Demonstrate Dependency Injection by using Constructor Injection.
As the name suggests, Constructor Injection allows us to achieve Dependency Injection by creating a constructor in the class. In Constructor Injection, we inject the dependency of the class through the constructor.
Let’s see this in action:
First, we will create an interface IMessanger
:
public interface IMessanger
{
void SendMail(string to, string subject, string mailbody);
void SendSMS(string mobileNumber, string smsText);
void SpecialMessage(string message);
}
In the interface, we have 3 methods.
Next, we will create a class which implements the interface IMessanger
:
public class Messanger : IMessanger
{
public void SendMail(string to, string subject, string mailbody)
{
Console.WriteLine("Mail Sent to User");
}
public void SendSMS(string mobileNumber, string smsText)
{
Console.WriteLine("SMS Sent to Mobile");
}
public void SpecialMessage(string message)
{
Console.WriteLine(message);
}
}
Let’s create a class NotificationServiceWithConstructorInjection
.
We will then create a constructor of the class to inject the dependency.
public readonly IMessanger _messanger;
public NotificationServiceWithConstructorInjection(IMessanger messanger)
{
_messanger = messanger;
}
Here, NotificationServiceWithConstructorInjection
class depends upon IMessanger, which we are injecting through its constructor.
So, the class NotificationServiceWithConstructorInjection
calls all the methods of the Messanger
class.
public class NotificationServiceWithConstructorInjection
{
public readonly IMessanger _messanger;
public NotificationServiceWithConstructorInjection(IMessanger messanger)
{
_messanger = messanger;
}
public void SendEmailToUser(string to, string subject, string mailBody)
{
_messanger.SendMail(to, subject, mailBody);
}
public void SendSMSToUser(string mobileNo, string smsText)
{
_messanger.SendSMS(mobileNo, smsText);
}
public void SpecialMessage(string message)
{
_messanger.SpecialMessage($"{message}");
}
}
Here, we create the constructor of the NotificationServiceWithConstructorInjection
class. In the constructor, we pass the parameter of the type IMessanger
interface.
Finally, we will call the methods of NotificationServiceWithConstructorInjection
class from the main method, like this:
string toEmail = "abc@domain.com";
string mailSubject = "Test Mail";
string mailBody = "This is a test Mail";
string mobileNo = "1111111111";
string smsText = "SMS Text";
string specialMessage = "Happy New Year";
IMessanger messanger = new Messanger();
NotificationServiceWithConstructorInjection notificationServiceWithConstructor =
new NotificationServiceWithConstructorInjection(messanger);
notificationServiceWithConstructor.SendEmailToUser(toEmail, mailSubject, mailBody);
notificationServiceWithConstructor.SendSMSToUser(mobileNo, smsText);
notificationServiceWithConstructor.SpecialMessage(specialMessage);
So, in this implementation, we are not instantiating the class Messanger
. In this way, the class NotificationServiceWithConstructorInjection
and Messanger
don’t have any tight coupling, instead, we are using a constructor of the interface to create the dependency.
Using Property Injection
Another way of implementing dependency injection is by using property injection. In this approach, we create dependency through a public property of the client class. We can call this approach Setter Injection as well.
Let’s see this demonstration:
public class NotificationServicePropertyInjection
{
public IMessanger Messanger { get; set; }
public void SendEmailToUser(string to, string subject, string mailBody)
{
Messanger.SendMail(to, subject, mailBody);
}
public void SendSMSToUser(string mobileNo, string smsText)
{
Messanger.SendSMS(mobileNo, smsText);
}
public void SpecialMessage(string message)
{
Messanger.SpecialMessage(message);
}
}
We have a class NotificationServicePropertyInjection
and to execute the methods of the Messanger
class we use an auto-property of the type IMessanger
interface.
Now, we will call the methods from the Program
class.
string toEmail = "abc@domain.com";
string mailSubject = "Test Mail";
string mailBody = "This is a test Mail";
string mobileNo = "1111111111";
string smsText = "SMS Text";
string specialMessage = "Happy New Year";
IMessanger messanger2 = new Messanger();
NotificationServicePropertyInjection notificationServicePropertyInjection =
new NotificationServicePropertyInjection();
notificationServicePropertyInjection.Messanger = messanger2;
notificationServicePropertyInjection.SendEmailToUser(toEmail, mailSubject, mailBody);
notificationServicePropertyInjection.SendSMSToUser(mobileNo, smsText);
notificationServicePropertyInjection.SpecialMessage(specialMessage);
Here, we are instantiating the Messanger
class. And then assigning this to the property that we use in NotificationServicePropertyInjection
class. So, in this way, we can implement Dependency Injection using auto-property.
Dependency Injection using Method Injection
Finally, the third option to implement Dependency Injection in C# is method injection. In this approach, we inject the dependency through a method parameter.
Let’s see this:
public class NotificationServiceMethodInjection
{
public void SendEmailToUser(string to, string subject, string mailBody, IMessanger messanger)
{
messanger.SendMail(to, subject, mailBody);
}
public void SendSMSToUser(string mobileNo, string smsText, IMessanger messanger)
{
messanger.SendSMS(mobileNo, smsText);
}
public void SpecialMessage(string message, IMessanger messanger)
{
messanger.SpecialMessage(message);
}
}
Here, we are passing the IMessanger
interface type to the methods and then calling the method of the Messanger
class. And, in this way, we achieve Dependency Injection.
string toEmail = "abc@domain.com";
string mailSubject = "Test Mail";
string mailBody = "This is a test Mail";
string mobileNo = "1111111111";
string smsText = "SMS Text";
string specialMessage = "Happy New Year";
NotificationServiceMethodInjection notificationServiceMethodInjection =
new NotificationServiceMethodInjection();
IMessanger messanger1 = new Messanger();
notificationServiceMethodInjection.SendEmailToUser(toEmail, mailSubject, mailBody, messanger1);
notificationServiceMethodInjection.SendSMSToUser(mobileNo, smsText, messanger1);
notificationServiceMethodInjection.SpecialMessage(specialMessage, messanger1);
Finally, we call the methods of the NotificationServiceMethodInjection
class and we pass the IMessanger
type parameter to the methods.
How to Effectively Implement Dependency Injection in .NET 5?
Conclusion
In this blog, we learnt about Dependency Injection in C#. Also, we learnt 3 different ways to implement the Dependency Injection. The three different ways are constructor Injection, Property Injection and Method Injection.