I will cover most of the topics about Dependency Injection in this Series. This series contains four parts as follows

Let start with Part 1: Understanding why we need to use Dependency Injection? In detail explanation

Before we learn about Dependency Injection, we understand why we need and where does Dependency Injection will be used.

When designing an enterprise application we need to consider so many requirements it may be functional or non-functional. Functional requirements are based on a project to project, but in a case of choosing non-functional requirements, we need to understand the system and its future enhancements.

Some of the most common Non-functional requirements such as

  • Maintainability: Once system is build and in case of any issues, it must be very easy to discover and fix it. Or in case of any modifications, system should be in a flexible to accept any modifications or extensions.
  • Testability: System should build such that any modifications or enhancements can be tested without any major implementations on testing framework.
  • Loose Coupling: This is a common non-functional requirement these days every client dreams for. Based on this requirement, any component in the system should not tightly depends on other component. These components should be in a position to be plugin to other system without any pain. This also helps in parallel development independently by different teams each component or module.
  • Late Binding: This requirement is not suitable for major set of applications. As per this requirement, System can accept any plugins without any re-compiling at runtime.

Let’s dig into some sample code below to understand how above requirements will be useful in log run for any application especially complex applications.

public class MSSQLRepository 
    { 
        string _connectionString = string.Empty; 
 
        public MSSQLRepository(string connString) 
        { 
            _connectionString = connString; 
        } 
 
        public IEnumerable<Employee> GetAllEmployees() 
        { 
            // Implementing logic to fetch employee information 
        } 
    } 
 
 
    public class EmployeeBusiness 
    { 
        MSSQLRepository _repository = null; 
 
        public EmployeeBusiness() 
        { 
            _repository = new MSSQLRepository("<specific connection string>"); 
        } 
 
        public IEnumerable<Employee> GetAllEmployees() 
        { 
            return _repository.GetAllEmployees(); 
        } 
    }

In the above code we are trying to fetch all employees from the database, for this we have a EmployeeBusiness class which acts as business layer and  MSSQLRepository class acts as repository or data layer connecting to a database and fetching all employees information.

Till now everything good and the above code perfectly executes and serves our requirement to get all employees information from the database but can you guess what are the problems with this code? Let’s list out some below

  • Let’s assume MSSQLRepository class is used by many business classes to connect the database and do respective actions. Now, based on the new requirement from a client we need to get more information from the constructor of this class. But if we change the existing constructor of this class by adding new parameters will also need to change in all the respective business classes wherever this class is initialized, and this leads to maintainability issue.
  • If you want to create test cases for this and in case if we are working with any test case which inserts it will create a junk data or we need to maintain a new testing database as business class internally initialize the repository class and calls the respective method. Maintaining testing database is a nightmare and every time it should restore to execute these test cases for next run.
  • As these are in the same component and also MSSQLRepository tightly coupled with EmployeeBusiness class. If we want to change the MSSQLRepository with some OracleRepository we need to change all the business classes and methods as not sure this new class will have same method names.

Now, let’s re-modify the above code to address all the above issues

public interface IRepository 
        { 
            IEnumerable<Employee> GetAllEmployees() 
        }  
 
 
        public class MSSQLRepository : IRepository 
        { 
            string _connectionString = string.Empty; 
 
 
            public MSSQLRepository(string connString) 
            { 
                _connectionString = connString; 
            } 
 
 
            public IEnumerable<Employee> GetAllEmployees() 
            { 
                // Implementing logic to fetch employee information  
            } 
        } 
 
        public class EmployeeBusiness 
        { 
            IRepository _repository = null; 
 
 
            public EmployeeBusiness(IRepository repository) 
            { 
                _repository = repository; 
            } 
 
 
            public IEnumerable<Employee> GetAllEmployees() 
            { 
                return _repository.GetAllEmployees(); 
            } 
        }

Following are the changes can be observed in the above code

  1. We introduced new Interface IRepository and which is inherited by our repository class MSSQLRepository.
  2. Removed initializing the repository class in the business class and added a new parameter to the constructor where it expecting repository object will be sent by calling method.

Now let’s understand how the above code solves all the problems which we listed with previous example code.

  • As Business class is not directly dependent on repository class and also business class is not responsible for any initialization of repository object we can change the constructor or any logic in the MSSQLRepository class with following IRepository contract. This way we solved maintainability issue here.
  • If we want to create a test cases for this business class, no need to maintain any test database instead, we can inject or send by creating IRepository object by creating any custom repository class (that inherited by IRepository) by implementing any mock data and send this object via. Business class constructor. This way we also solved testability issue.
  • Now business and repository classes are not tightly coupled (where in previous example it was tightly coupled) due to introducing Interfaces, these classes can be placed in different components I.e., Business component, Interface component and Repository and can develop these components in parallel. With this Loose coupling issue also solved.
  • If the client come with new requirement saying, he is now moving all the database from MS SQL Server to Oracle then, we can create new class OracleRepository and implement IRepository interface. As these business classes are expecting an object of type IRepository there is no need to change any logic here instead we should change the calling method or component with this new class.

Till now we discussed much about non-functional problems and understand how to overcome those problems with simple examples. Now the question is, where exactly this Dependency Injection (DI) fits.  Dependency Injection (DI) is a technique where it injects the dependent objects to the other classes via. Constructors.

Dependency Injection (DI) also can control the lifetime of the created object like, once I created the object can be reused for rest of the requests for that object throughout the application life or request lifetime, as object will be reused for the same request.

We have many components or tools available in the market which creates and maintains these objects based on their lifetime configured. For example Unity, AutoFac etc..,

We are now having a good understanding on common design problems, solutions to these problems and also understanding where exactly the Dependency Injection fits in the complex Enterprises application.

Next part will see how in real time this Dependency Injection will be implemented using Unity.

Part 2: Understanding how to implement Dependency Injection using Unity