Inversion of Control is a Design Principle that helps to invert the control of object creation.
Dependency injection design pattern is the software development design pattern based on the Inversion of control design principle used to decouple the objects from each other. Inversion of Control (IOC) and Dependency Injection helps to decouple the application and follow the SRP (Single responsibility principle) principle of software development. In other words, the main goal of dependency injection is to remove the dependency between the two objects.
Inversion of Control (IOC)
Let’s first understand Inversion of Control (IOC) then we can clearly understand Dependency Injection.
Let’s say there is a Customer class and when customer. Add is initiated it steps through the following path:
- Creates object for Database Server (DAL)
- Calls Validate function to validate
- Then calls DAL.AddToDb()
Now In this case we just have one database and the function is calling just DatabaseServer and inserting the values. Lets we add another Database in our system say OracleDbase. Now we can extend our code as follows:
In our DAL we will add an interface that both our DatabaseServer and OracleDbase will implement and the Customer class can reference the interface which will implement runtime polymorphism by either executing DatabaseServer or OracleDbase.
So in Customer Class, we can call the corresponding server based on the parameters passed on to the customer object.
So if we look at Customer class what is it doing:
The customer is receiving the input from outside and deciding on which object to create looking at the values passed to it and then call Validate and then Add. Here the customer is deciding to create the object.
So now the question is this the work of the customer object to decide to create a new object?
No the Customer object’s work is not to make decisions or to create objects, it is now loaded up with too much work and violates the Single Responsibility Principle (SRP). A good code is that code that takes care of its logic rather than overloading itself with unconcerned logic.
Here Customer is overloaded with the code to decide which Data Access layer to use is unconcerned logic. This makes customer class tightly coupled to the Data access layer changes and in the long run, this code becomes difficult to maintain.
The best way Customer class function is by just focusing on its tasks to validate and calling the Add function of DataAccess not worrying about which object to initiate to call the Add function. So now this task or control of making the decision has to be shifted away or inverted from the Customer class to some external entity.
Let’s see how we can pass on the task to the external entity by making some code modifications.
Instead of making decisions or letting the Customer class decide which object to instantiate, we passed on the whole object. So now Customer class won’t have to worry about making decisions it simply can invoke DAL.AddToDb() without worrying about which database it is. The decision is shifted outside of the Customer Class to the main function, deciding what database it needs to execute.
So this shifting the control of business logic from the class to the external entity by keeping the class aligned to the Single Responsibility Principle is called the IOC (Inversion of Control) Principle. This will help decouple the system with cleaner code and if there are any changes in the Data Access Layer the Customer class code is unchanged which makes the code more maintainable.
Inversion of Control principle can be maintained in various ways such as the use of Service Locator, Events, Delegates, or Dependency Injection.
Dependency Injection Design Pattern
Dependency injection is the technique that helps to inject a dependent object of a class. In the above example, we passed on the Dal object to the Customer Class through a constructor, and this method/design pattern is called Dependency Injection Design Pattern.
Well, now we can see the object creation process is taken away from the Customer class but still the problem remains the same for UI, which is creating the class and so it is now tightly coupled with the user interface. If we have to change the DAL then again we will have to make changes in UI, so that means we still are in the same spot and we just moved the ball from the Business layer to the UI layer.
To have a decoupled architecture we can further move the process of object creation away from the UI to an external third-party framework that is configurable and easy to use. There are a lot of frameworks that can help the dependency injection one of the most common frameworks that come from Microsoft Patterns and practices is the unity framework. Unity application block is lightweight and time-tested which is the one that I will be explaining in this post.
We can download the Unity application block through Nuget Package Manager and use it. (I am using Unity.NetCore (4.0.3) & Unity.Configuration (5.11.2))
Here we have used Unity that helps create a container that holds the class objects and the dependent objects and that can be injected in the class that wants them without the need to change the class. Since we have tightly coupled UI where we were still creating new objects of the DAL layer we have now removed that part using Unity.
Note: In this demo we are writing the Unity code in the UI and might seem like UI is overloaded however this is not the case. This code has to be moved to the startup section of the code Global.asax or App.xaml.cs etc.
Since Unity is a third-party container and won’t know what classes or interfaces are operating in your application, we need to let the container be aware of the classes or interfaces.
So now in our case we will register our objects in this container and use “RegisterType<ClassName>” or we will register it for Customer class “RegisterType<Customer> which will be initiating a DAL object. When we ask the customer object from the Unity container using.Resolve<Customer>. This returned the customer object with the loaded and instantiated OracleDbase object. Sweet…
Wow now finally our Application is decoupled… But hey did you notice, we got the OracleDbase object but what about our initial DatabaseServer object where is it gone and how can we access it. Well, there you go this shows there is more work to do.
Since the OracleDbase was loaded after the DatabaseServer the last loaded object was only picked up. To resolve this we need to identify these with their separate unique keys.
Here we create a new unique key for Customer DbServer call it “CustDBServer” and inject it into the unity container along with DB Server. Similarly, create a new unique key for Customer and OracleDB call it “CustOracle” and inject it into the unity container along with OracleDb.
Now we have successfully removed the dependency from the UI layer to the Unity container and the parameters can be passed from the config file or from the XML file so that our classes will be fully decoupled.
Let’s move ahead one more step and remove the hard-coded names from the program and load the configurations from the XML.
Loading Unity Container from config file for Dependency Injection
In this example, we will be loading the Unity container from configuration file. For that
- Add App.config in the application and configure unity mapping to the inject the class with its corresponding interface.
- Use Microsoft.Practices.Unity.Configuration to read unity configuration and load objects to Unity collection.
- Use System.Configuration to read app.config
In the configuration you have to map the database that you want to inject to and use. In this case I have mapped interface (Idal) to the DatabaseServer class under DAL namespace. If I would like to change it to oracle then I will just change DatabaseServer to OracleDbase.
Now after the config is setup we just need to declare the Unity container and load the configuration. Then you can use the class (object) that has used interface in constructor of the injected objected then we can ask the Unity container to resolve. And wow the object is injected in the called object.
Now we have successfully removed the dependency from all the classes of the project, we have decoupled the application and have a cleaner and more manageble code.
Further Extention: If you want them to be accessed separately you can give them names and call accordingly
<configuration>
<configSections>
<section name="unity"
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="DAL.Idal, DAL"
mapTo="DAL.DatabaseServer, DAL" name="DbServer" />
<register type="DAL.Idal, DAL"
mapTo="DAL.OracleDbase, DAL" name="OraDb" />
</container>
</unity>
<startup>
<supportedRuntime version="v5.0" sku=".NETFramework,Version=v5.0" />
</startup>
And call the Resolve using its name
string strDBToUse ="DbServer"; // You can get this from config file or
Customer obj = uContainer.Resolve<Customer>(strDBToUse);
There is another good article about Unity container called “How to configure the Unity Container” in the C# corner you can refer to.
[…] of customers from UI to the factory class which matches the IOC (Inversion of Control) principle. There are various ways to achieve IOC principles like using Dependency Injection, Delegates, and so on. In this example we used Factory patter to achieve IOC principle, Factory […]