Inversion of control (IOC) and Dependency Injection (DI) work hand in hand and make our application more loosely coupled and easy to expand. It is strongly recommended to follow SOLID principles when it comes to development. This article will not be very theoretical but will be more of a tutorial to showcase the existing problems with tightly coupled applications, how to make the application loosely coupled and achieve inversion of control via dependency injection, solve the problem of resolving dependency of a dependency in a three-layered/n layered project architecture using unity framework.
Problem
While working on a three-layered architecture, there could be situations where applications at higher level modules/layers/classes are dependent on lower-level modules. If we consider a basic simplistic example, an application can have a presentation layer, a business layer, and a data access layer in a three-layered architecture. Presentation layer talks to the business layer, the business layer in turn talks to the data access layer. To call a method of the business layer in the presentation layer, we need to create an object of business layer class in the presentation layer and then call that method as needed. To call the method of a class in the data access layer, the business layer class needs to create an object of the class in the data access layer and then invoke that method. The business layer communicates with the data access layer because due to architectural constraints and flexibility, we do not want our presentation layer talking to the data access layer as shown below.
Considering that the readers of this tutorial already know how to resolve dependency of modules, the presentation layer itself needs to not create an object of the business layer but delegate this responsibility to any third-party container, and when the instance is needed then that object is created for the presentation layer, i.e., dependency injected and methods of business layers could be accessed via that. The same goes for communication between the business layer to the data access layer. This is where Unity comes into the picture. Unity acts as a container for this object creation and dependency resolution. Our problem is a bit different. Using unity at the presentation layer, we can resolve the dependency of the business layer, but what about the data access layer? How do we resolve the dependency on the data access layer in the business layer? Do we need to again write a container in the business layer? One way to achieve this is already explained in one of my
previous articles, where we can make use of MEF (Managed Extensibility Framework), but in this tutorial, we’ll use a very simple way to do this. Let’s write some code, first to see the problem, and then towards a step-by-step solution.
Create Application Without DI
Since the focus area of this article is to explain the use of unity to resolve dependency of dependency in a simplistic way, we’ll not create a large application, but a small three-layered console application with only one class in each layer and one method in each class for the proof of concept. One can create MVC or any other application or can use this solution as a POC in any big application.
Step 1
Open Visual Studio. Create a console application and name it Presentation, add a class library and name it Business, add another class library, and name that Data. So, we segregate our layers with these class libraries, where a Business class library is for a Business layer and the Data class library is for the Data access layer. The solution should look like something as follows. I have named the solution as “WithoutDI”.
Remove the default classes named Class1.cs from Business and Data class libraries.
Step2
Now, add a class named BusinessClass in the Business project and DataClass in Data project. Add a method named GetData in the DataClass and return any string from that method. So, the implementation of the class looks as follows.
- namespace Data
- {
- public class DataClass
- {
- public string GetData()
- {
- return "From Data";
- }
- }
- }
Step 3
Now, our requirement is to get this data coming from the GetData method into our presentation layer and show it on the console. The straightforward way is that we call a method of Business class from the presentation layer's Program.cs that in turn will call this GetData method from DataClass. To achieve this, we first need to add the reference to the Business project in the Presentation console application and reference of Data project in the Business class library.
Step 4
Now, to access the GetData method of Data project DataClass from BusinessClass, we first need the instance of DataClass in BusinessClass. We create the instance in BusinessClass constructor and then there should be a method in Business class that then makes use of this DataClass instance to call the GetData method to return the string. So, the implementation looks as follows.
- using Data;
- namespace Business
- {
- public class BusinessClass
- {
- DataClass _dataClass;
- public BusinessClass()
- {
- _dataClass = new DataClass();
- }
- public string GetBusinessData()
- {
- return _dataClass.GetData();
- }
- }
- }
Step 5
Now, to class this GetBusinessData method of Business class from the presentation layer, we again need to create an instance of BusinessClass class in the presentation layer and call the method. To create an instance of BusinessClass in the main method or Program.cs and call the GetBusinessData via that instance looks like:
- using System;
-
- namespace Presentation
- {
- class Program
- {
- static void Main(string[] args)
- {
- Business.BusinessClass businessClass = new Business.BusinessClass();
- string data = businessClass.GetBusinessData();
- Console.WriteLine(data);
- Console.ReadLine();
- }
- }
- }
When we run the application, we get our desired output as shown below.
That means that our data comes from DataClass’s GetData() method. Our application runs fine, but the question is, is it following SOLID principles? Is my application loosely coupled and autonomous? Is my application robust? If we look closely and try to answer these questions, the answer is, NO.
Application violates the Single Responsibility Principle where classes are also doing an additional job of creating objects of dependent classes.
The application violates the Open-Close principle as, in case the constructor implementation changes in the classes, the calling class will have to modify its code to that change which may break the application or may not be feasible.
The application violates the Interface Segregation Principle indirectly, and the testability of the application is very poor as we do not have interfaces defined for the classes that serve as a contract.
The application violates the Dependency Inversion principle as classes are dependent on other class instances and are directly creating instances in the class. Imagine a situation where instance creation of DataClass fails, due to which Business class constructor will also fail to initialize and throw an error, which is not at all acceptable.
So, four out of five principles are violated. Moreover, the application is not testable w.r.t. unit tests. The application is tightly coupled. Let’s try to resolve these issues one by one with the help of the Unity Framework and also proceed to see how we can resolve the dependency of a dependency.
Introduce Unity in the Application
Time to introduce Unity in the application. Unity Framework comes as a NuGet package, so we’ll install it via Package Manager Console. Open Tools in Visual Studio, navigate to Nuget Package Manager, and open Package Manager Console as shown in the below image.
When the package manager console is opened, type command Install-Package Unity to get the latest version of the Unity framework. Make sure the Presentation project is selected as the default project in the console. After typing the command when we press enter, the Unity package is installed for the presentation project. The latest version that I got is 5.7.3. it may vary and depend on when you are implementing this based on the latest versions released.
There would be one package.config file created in the application where this Unity package would be referenced and the package itself would be downloaded in the file system in packages folder and the same would be referenced automatically in the Presentation project.
Dependency Injection via Unity
Let’s do some modification in the Presentation layer and instead of calling the BusinessClass method from the Main method, let’s add a class named Initiator and call the method from there. We could have done this earlier, but we missed it, so let’s do it now. This is just to understand more clearly, how we resolve dependencies. So, add a class named Initiator and add the following code.
- using Business;
- namespace Presentation
- {
- public class Initiator
- {
- BusinessClass _businessClass;
- public Initiator()
- {
- _businessClass = new BusinessClass();
- }
- public string FetchData()
- {
- return _businessClass.GetBusinessData();
- }
- }
- }
Code for Program.cs becomes as follows,
- using System;
-
- namespace Presentation
- {
- class Program
- {
- static void Main(string[] args)
- {
- Initiator initiator = new Initiator();
- string data = initiator.FetchData();
- Console.WriteLine(data);
- Console.ReadLine();
- }
- }
- }
The output and logic remain the same, we just moved a few pieces from Program.cs to Initiator class and in the Main method now use this Initiator class instance to fetch data.
So, the problem here now is, Program.cs Main() method creates an instance of Initiator class, Initiator class creates an instance of BusinessClass, and Business class creates an instance of DataClass to fetch data. Let’s give this responsibility of instance creation to someone else; i.e. Unity, and inject the dependency in the defined constructors via Interfaces. Yes, we now need to create interfaces and define the respective methods. Let’s do it step-by-step.
Step1
Create an interface named IData in the Data project and define the GetData () method there as shown below.
- namespace Data
- {
- public interface IData
- {
- string GetData();
- }
- }
Now, implement this interface in DataClass as shown below,
- namespace Data
- {
- public class DataClass : IData
- {
- public string GetData()
- {
- return "From Data";
- }
- }
- }
Step2
Now, come to the Business project and define an interface named IBusiness and define the GetBusinessData() method there as shown below.
- namespace Business
- {
- public interface IBusiness
- {
- string GetBusinessData();
- }
- }
Implement this interface in BusinessClass as follows,
- using Data;
- namespace Business
- {
- public class BusinessClass
- {
- DataClass _dataClass;
- public BusinessClass()
- {
- _dataClass = new DataClass();
- }
- public string GetBusinessData()
- {
- return _dataClass.GetData();
- }
- }
- }
Now, let’s assume that Business class will no longer take this responsibility of object creation and this dependency would be injected in BusinessClass constructor on runtime and we’ll have an object at runtime to call GetData method of DataClass. So, our Business class looks something like the following,
- using Data;
-
- namespace Business
- {
- public class BusinessClass : IBusiness
- {
- IData _dataClass;
-
- public BusinessClass(IData dataClass)
- {
- _dataClass = dataClass;
- }
- public string GetBusinessData()
- {
- return _dataClass.GetData();
- }
- }
- }
It is pretty straightforward. We declare IData instance local variable and expect IData instance in the constructor of BusinessClass at runtime, which we assign to our local variable and in the method GetBusinessData(), we make use of this local variable assuming it would be initialized well in advance, we call the GetData() method. Note that no “new” keyword here is used to create an instance and now BusinessClass also does not takes this responsibility of creating objects of DataClass. This code will still not work. We need to do some homework in our presentation layer as well.
Step 3
Move to Presentation project and do the same thing as we did in the Business layer for DataClass, but now in Initiator class for a Business layer. So, our Initiator class looks like as shown below,
- using Business;
- namespace Presentation
- {
- public class Initiator
- {
- IBusiness _businessClass;
- public Initiator(IBusiness businessClass)
- {
- _businessClass = businessClass;
- }
- public string FetchData()
- {
- return _businessClass.GetBusinessData();
- }
- }
- }
This is also easy to understand. We declare IBusiness instance local variable, then in the constructor, we assume that we get the pre-initialized instance of a business class and assign the same to our local variable and call GetBusinessData() method via that. Note, that we completely removed the “new” keyword from here and this class also does not take this responsibility to create objects. Our job is still not done. We still have Main() method in the program.cs class that creates an object of Initiator class via “new” keyword and class the FetchData() method. Our goal is to completely get rid of this “new” keyword and make sure classes follow the Single Responsibility Principle.
Step4
Add a new class named DependencyInjector in the Presentation project and add the following code to it.
- using Unity;
- using Unity.Lifetime;
-
- namespace Presentation
- {
- public static class DependencyInjector
- {
- private static readonly UnityContainer UnityContainer = new UnityContainer();
- public static void Register<I, T>() where T : I
- {
- UnityContainer.RegisterType<I, T>(new ContainerControlledLifetimeManager());
- }
- public static void InjectStub<I>(I instance)
- {
- UnityContainer.RegisterInstance(instance, new ContainerControlledLifetimeManager());
- }
- public static T Retrieve<T>()
- {
- return UnityContainer.Resolve<T>();
- }
- }
- }
This DependencyInjector class is a generic class that takes care of resolving types and registering types. It makes use of Unity to register an instance of any type coming to it. We could have made it specific to our classes and interfaces, but it is always better to be generic to entertain whatever new types come to our application in the future.
To define and register our concrete types, i.e., IBusiness and Business class, add another class named Bootstrapper to the presentation project. This class acts as its name, i.e., Bootstrapper for our application, i.e., first-class to resolve dependencies beforehand as soon as our application loads. So, add Bootstrapper.cs and add the following code to it.
- using Business;
- namespace Presentation
- {
- public static class Bootstrapper
- {
- public static void Init()
- {
- DependencyInjector.Register<IBusiness, BusinessClass>();
- }
- }
- }
This class just calls the generic Register method of DependencyInjector class and requests to resolve dependency of BusinessClass, so that when needed, the instance of Business class would be supplied.
Step 5
In the Main method, now just call this Init() method of Bootstrapper class to register the types and get an instance of Initiator class via Retrieve method of DependencyInjector class. We need this Initiator instance to call the FetchData method of Initiator class. So following is the code of our Program.cs class.
- using System;
- namespace Presentation
- {
- public class Program
- {
- static void Main(string[] args)
- {
- Bootstrapper.Init();
- Initiator initiator = DependencyInjector.Retrieve<Initiator>();
- string data = initiator.FetchData();
- Console.WriteLine(data);
- Console.ReadLine();
- }
- }
- }
Simple, crisp, and clear. Note that we got rid of the “new” keyword from here also and the main responsibility of this class is initialization and application start-up.
In a nutshell, we did the following,
- Introduced the generic DependencyInjector class to take care of registering/resolving types.
- Introduced Bootstrapper class that calls DependencyInjector class methods in its Init() method for registering concrete types.
- In the Main method of Program.cs invoked the Init method of Bootstrapper class, so that types are registered and resolved at the start of the application.
- Called our FetchData() method from the Initiator class.
To, me everything looks fine and we are all set to run the application.
Step6
Run the application by hitting F5. We assumed everything would work fine as we took care of dependencies, but wait a minute -- look what we got. We got the following run time error.
When you check the InnerException, the error is obvious and self-explanatory. It says, “- InnerException {"The current type, Data.IData is an interface and cannot be constructed. Are you missing a type mapping?"} System.Exception {System.InvalidOperationException}”
Yes, you are right. We took care of registering BusinessClass with IBusiness. We took care of resolving the Initiator class instance but what about DataClass? Remember, we removed “new” from BusinessClass constructor as well when we try to get DataClass instance, but we have not yet registered the type nor resolved it to be used when needed.
The solution is that we need to register type for DataClass as well so that we get its instance when needed. But how to do it? We cannot access or reference the Data project in the presentation layer as it will violate our layered architecture. So, the only place is a Business project. But again, if we do it altogether as we did in the Presentation layer, it will not make sense and will have code duplication and two bootstrappers in the application. One way is MEF, that I already explained in one of my
previous articles, but that method is a bit complex. Let’s explore how we can overcome this situation without referencing Data projects in the presentation project, without code duplication, without multiple and confusing/hard to manage bootstrappers and without SOLID/coupling violation.
Resolve Dependency on Dependency using Unity Extensions
Unity provides this flexibility to resolve dependency of dependencies without structure violation via UnityContainerExtensions as shown below:
- namespace Unity.Extension
- {
- public abstract class UnityContainerExtension: IUnityContainerExtensionConfigurator
- {
- protected UnityContainerExtension();
-
- public IUnityContainer Container { get; }
- protected ExtensionContext Context { get; }
-
- public void InitializeExtension(ExtensionContext context);
- public virtual void Remove();
- protected abstract void Initialize();
- }
- }
This class is part of Unity. Abstractions dll and contains an abstract method named Initialize(). Abstract method means we can override this method and write our custom initialization logic. So, let’s do that.
Create a class named DependencyOfDependencyExtension in the Business project. You can name the class as per your choice. I named the class in this way for the sake of understanding. Install Unity package in the Business project in the same way as we did for the presentation project. Do not forget to choose Business as the default project in the package manager console as shown below.
Step1
Once Unity is added to the project as it was in the presentation layer, add the following namespaces to our newly created DependencyOfDependencyExtension class:
- using Data;
- using Unity;
- using Unity.Extension;
Now, inherit the class from UnityContainerExtension class present in Unity.Extension namespace of Unity.Abstractions assembly and override its Initialize method as follows to register DataClass type with IData.
- using Data;
- using Unity;
- using Unity.Extension;
-
- namespace Business
- {
- public class DependencyOfDependencyExtension : UnityContainerExtension
- {
- protected override void Initialize()
- {
- Container.RegisterType<IData,DataClass>();
- }
- }
- }
Step 2
Now, we must make our presentation layer know about this extension. So, move to the presentation layer and in the DependencyInjector class add a new generic method named AddExtension() to add new extensions as shown below:
- public static void AddExtension<T>() where T : UnityContainerExtension
- {
- UnityContainer.AddNewExtension<T>();
- }
Do not forget to add using Unity.Extension;namespace to this class to access UnityContainerExtension class. The complete class is as follows.
- using Unity;
- using Unity.Extension;
- using Unity.Lifetime;
-
- namespace Presentation
- {
- public static class DependencyInjector
- {
- private static readonly UnityContainer UnityContainer = new UnityContainer();
- public static void Register<I, T>() where T : I
- {
- UnityContainer.RegisterType<I, T>(new ContainerControlledLifetimeManager());
- }
- public static void InjectStub<I>(I instance)
- {
- UnityContainer.RegisterInstance(instance, new ContainerControlledLifetimeManager());
- }
- public static T Retrieve<T>()
- {
- return UnityContainer.Resolve<T>();
- }
- public static void AddExtension<T>() where T : UnityContainerExtension
- {
- UnityContainer.AddNewExtension<T>();
- }
- }
- }
Step3
We are almost done. Now add concrete type for this extension in Bootstrapper’s class Init method as follows,
- using Business;
- namespace Presentation
- {
- public static class Bootstrapper
- {
- public static void Init()
- {
- DependencyInjector.Register<IBusiness, BusinessClass>();
- DependencyInjector.AddExtension<DependencyOfDependencyExtension>();
- }
- }
- }
The job is done; just run the application and we will see our desired output as shown below:
In this way, we resolved dependency of dependency; that is dependency (DataClass) of dependency (BusinessClass) to the presentation layer.
Summary
Let’s do a quick summary of what we did in our application and complete the tutorial.
- We created a three-layered basic architecture with presentation, business, and data access layer. The architecture was tightly coupled and violated SOLID.
- We introduced Unity to resolve dependency between presentation and business layer. Thereafter we used constructor injection to inject dependencies via interfaces.
- We resolved dependency of dependency using Unity Extensions so that our architecture was not breached.
- We got rid of “new” keywords and delegated the responsibility of object creation to Unity container.
- We achieved an inversion of control via dependency injection.
- Every class has a single responsibility and is open to extension and not modification.
- We achieved Abstraction with the help of interfaces.
Conclusion
In this tutorial, we tried to learn dependency injection with the help of a simple example. The example is very basic, but the concept could be applied in MVC, Web API, or any enterprise-level application to resolve dependencies and achieve inversion of control with dependency injection. We also resolved the dependency of dependencies with unity extensions. There could be more methods to resolve dependencies like property injection or a service locator. We used constructor injection in our application. One can make use of other containers instead of Unity. I used Unity as I am more comfortable with it. I hope you enjoyed the article. Happy coding 😉
a