Back to: Design Patterns in C# With Real-Time Examples
Inversion of Control using Dependency Injection Pattern in C#
In this article, I am going to discuss the Inversion of Control using the Dependency Injection Pattern in C# with an example. Please read our previous article where we discussed how to achieve Inversion of Control using the Dependency Inversion Principle, in that article we created and used abstraction to make the classes loosely coupled. Here, in this article, I am going to implement the Dependency Injection Design pattern to move the dependency object creation logic completely out of the class. This is our third step in making the classes completely loosely coupled.
What is Dependency Injection?
Whenever we are injecting an instance of a class into a class that depends on it, it is called dependency injection. The Dependency Injection (DI) design pattern is a software design pattern that is used to implement Inversion of Control (IoC) where it allows the creation of dependent objects outside of a class and provides those objects to a class in different ways. Using the Dependency Injection design pattern, we can move the dependent object creation and binding outside of the class that depends on it.
DI is a great way to reduce the tight coupling between software components. DI also enables us to better manage future changes and other complexity in our software. The dependency Injection design pattern involves 3 types of classes.
Client Class:
The class which depends on the service class is called the Client Class or dependent class.
Service Class:
The class which provides the service to the client class is called a Service Class or dependency class
Injector Class:
The class which is used to inject the service class object into the client class is called an Injector class.
The following diagram illustrates the relationship between these classes (Client Class, Service Class, and Injector Class).
As you can see in the above diagram, the injector class creates an object of the service class and injects that object into a client class, and the client class then uses that service class object. In this way, the Dependency Injection Design pattern separates the logic or responsibility of creating an object of the service class (Dependency class) out of the client class (dependent class).
Types of Dependency Injection:
As you have seen in the above diagram, the injector class injects the service (dependency object) into the client class (dependent class). The injector class injects dependencies broadly in three ways: through a constructor, through a property, or through the method.
Constructor Injection:
In the constructor injection, the injector class supplies the service object (i.e. dependency object) through the client class constructor.
Property Injection:
In the property injection or we can say setter Injection, the injector class supplies the dependency object (i.e. Service object) through a public property of the client class.
Method Injection:
In method injection, the client class implements an interface that declares the method(s) to supply dependency and the injector class uses this interface to supply dependency to the client class.
We are going to work with the same example that we worked on in our last article. In the last article, we used the DataAccessFactory class inside the EmployeeBusinessLogic class to get an object of the EmployeeDataAccess object. Below are the classes we created in our previous article.
IDataEmployeeAccess.cs
namespace IoC_DIP_DI_Demo
{
public interface IEmployeeDataAccess
{
Employee GetEmployeeDetails(int id);
}
}
EmployeeDataAccess.cs
namespace IoC_DIP_DI_Demo
{
public class EmployeeDataAccess : IEmployeeDataAccess
{
public Employee GetEmployeeDetails(int id)
{
// In real time get the employee details from db
// but here we are hard coded the employee details
Employee emp = new Employee()
{
ID = id,
Name = "Pranaya",
Department = "IT",
Salary = 10000
};
return emp;
}
}
}
DataAccessFactory.cs
namespace IoC_DIP_DI_Demo
{
public class DataAccessFactory
{
public static IEmployeeDataAccess GetEmployeeDataAccessObj()
{
return new EmployeeDataAccess();
}
}
}
EmployeeBusinessLogic.cs
namespace IoC_DIP_DI_Demo
{
public class EmployeeBusinessLogic
{
IEmployeeDataAccess _EmployeeDataAccess;
public EmployeeBusinessLogic()
{
_EmployeeDataAccess = DataAccessFactory.GetEmployeeDataAccessObj();
}
public Employee GetEmployeeDetails(int id)
{
return _EmployeeDataAccess.GetEmployeeDetails(id);
}
}
}
The problem with the above example is that we used the DataAccessFactory class inside the EmployeeBusinessLogic class. Suppose, there is another implementation of the IEmployeeDataAccess class that is available for some reason and we want to use that new implementation class in the EmployeeBusinessLogic class. Then again we need to change the source code of the EmployeeBusinessLogic class. The dependency injection design pattern solves the above problem by injecting dependent objects via a constructor, property, or method.
The following figure illustrates the Dependency Injection design pattern implementation for the above problem.
As you can see in the above diagram of DI, the Employee Service class becomes an injector class that sets an object of service class (i.e. EmployeeDataAccess class) to the client class (i.e. EmployeeBusinessLogic class) either through constructor, property, or method to achieve loose coupling between the classes. Let’s understand each of these options with an example.
The Constructor Injection:
In the case of constructor injection, the injector class supplies the service object (i.e. dependency object) through the client class constructor. Let’s understand how to implement constructor injection with an example. First, modify the EmployeeBusinessLogic class as shown below.
namespace IoC_DIP_DI_Demo
{
public class EmployeeBusinessLogic
{
IEmployeeDataAccess _EmployeeDataAccess;
public EmployeeBusinessLogic(IEmployeeDataAccess dataAccess)
{
_EmployeeDataAccess = dataAccess;
}
public Employee GetEmployeeDetails(int id)
{
return _EmployeeDataAccess.GetEmployeeDetails(id);
}
}
}
In the above example, the EmployeeBusinessLogic class includes one constructor with one parameter of the type IEmployeeDataAccess. Now, the calling class must inject an object of IEmployeeDataAccess. Now to inject an object to the EmployeeBusinessLogic class let’s modify the program class as shown below.
namespace IoC_DIP_DI_Demo
{
class EmployeeService
{
static void Main(string[] args)
{
EmployeeBusinessLogic BL = new EmployeeBusinessLogic(new EmployeeDataAccess());
Employee employeeDetails = BL.GetEmployeeDetails(1);
Console.WriteLine();
Console.WriteLine("Employee Details:");
Console.WriteLine("ID : {0}, Name : {1}, Department : {2}, Salary : {3}",
employeeDetails.ID, employeeDetails.Name, employeeDetails.Department,
employeeDetails.Salary);
Console.WriteLine("Press any key to exist.");
Console.ReadKey();
}
}
}
Note: For the understanding purpose we rename the Program class name to EmployeeService.
As you can see in the above example, the EmployeeService class creates and injects the EmployeeDataAccess object into the EmployeeBusinessLogic class through the EmployeeBusinessLogic class constructor. Thus, now the EmployeeBusinessLogic class needs not to create an object of EmployeeDataAccess class using the new keyword or using the DataAccessfactory class.
The calling class (EmployeeService class) creates and sets the appropriate EmployeeDataAccess object to the EmployeeBusinessLogic class. In this way, EmployeeBusinessLogic and EmployeeDataAccess classes become more loosely coupled classes. As in the above example, we are injecting the object through a class constructor this approach is called constructor injection.
The Property Injection:
In the property injection or we can say setter Injection, the injector class supplies the dependency object (i.e. Service object) through a public property of the client class. Let us understand Property Injection with one example. Modify the EmployeeBusinessLogic class as shown below
namespace IoC_DIP_DI_Demo
{
public class EmployeeBusinessLogic
{
public IEmployeeDataAccess EmpDataAccess { get; set; }
public Employee GetEmployeeDetails(int id)
{
return EmpDataAccess.GetEmployeeDetails(id);
}
}
}
Modify the EmployeeService class as shown below
namespace IoC_DIP_DI_Demo
{
class EmployeeService
{
static void Main(string[] args)
{
EmployeeBusinessLogic BL = new EmployeeBusinessLogic();
BL.EmpDataAccess = new EmployeeDataAccess();
Employee employeeDetails = BL.GetEmployeeDetails(1);
Console.WriteLine();
Console.WriteLine("Employee Details:");
Console.WriteLine("ID : {0}, Name : {1}, Department : {2}, Salary : {3}",
employeeDetails.ID, employeeDetails.Name, employeeDetails.Department,
employeeDetails.Salary);
Console.WriteLine("Press any key to exist.");
Console.ReadKey();
}
}
}
As you can see in the above example, the EmployeeBusinessLogic class includes one public property named EmpDataAccess of type IEmployeeDataAccess where you need to set the instance of a class that implements IEmployeeDataAccess. So, EmployeeService Class creates and sets the EmployeeDataAccess instance using this public property.
The Method Injection:
In the method injection, dependencies are provided through methods. This method can be a class method or an interface method. The following example demonstrates method injection using the interface-based method. Add an Interface with the name IEmployeeDataAccessDependency.cs as shown below
namespace IoC_DIP_DI_Demo
{
interface IEmployeeDataAccessDependency
{
void SetDependency(IEmployeeDataAccess employeeDataAccess);
}
}
Modify the EmployeeBusinessLogic class as shown below.
namespace IoC_DIP_DI_Demo
{
public class EmployeeBusinessLogic : IEmployeeDataAccessDependency
{
public IEmployeeDataAccess EmpDataAccess { get; set; }
public Employee GetEmployeeDetails(int id)
{
return EmpDataAccess.GetEmployeeDetails(id);
}
public void SetDependency(IEmployeeDataAccess employeeDataAccess)
{
EmpDataAccess = employeeDataAccess;
}
}
}
Modify the EmployeeService class as shown below.
namespace IoC_DIP_DI_Demo
{
class EmployeeService
{
static void Main(string[] args)
{
EmployeeBusinessLogic BL = new EmployeeBusinessLogic();
BL.SetDependency(new EmployeeDataAccess());
Employee employeeDetails = BL.GetEmployeeDetails(1);
Console.WriteLine();
Console.WriteLine("Employee Details:");
Console.WriteLine("ID : {0}, Name : {1}, Department : {2}, Salary : {3}",
employeeDetails.ID, employeeDetails.Name, employeeDetails.Department,
employeeDetails.Salary);
Console.WriteLine("Press any key to exist.");
Console.ReadKey();
}
}
}
In the above example, the EmployeeBusinessLogic class implements the IEmployeeDataAccessDependency interface which includes the method SetDependency. So the injector class (EmployeeService Class) will now use this method to inject the dependent class (EmployeeDataAccess) into the client class.
As of now, we have used a couple of principles and patterns to achieve loosely coupled classes. In real-time projects, there would be many dependent clauses, and implementing these patterns would be time-consuming. Hence IoC Container helps us in such a scenario.
In the next article, I am going to discuss the IoC Container with examples. Here, in this article, I try to explain the Inversion of Control using the Dependency Injection Pattern in C# with Examples. I hope this Inversion of Control using Dependency Injection Pattern in C# article will help you with your needs. I would like to have your feedback. Please post your feedback, question, or comments about this Inversion of Control using the Dependency Injection Pattern in C# article.
..so we removed DataAccessFactory class when we use DI?