As Developers we may have come across the term ‘Dependency Injection’ as a design pattern that helps develop maintainable and de-coupled code. DI is also a way to implement the ‘D’ in SOLID principles. (SOLID as stated by Uncle Bob stands for: Single responsibility, Open closed principle, Liskov substitution principle, Interface segregation principle and Dependency Inversion). Often the association of 'Design Pattern' to anything that we have not dealt with before, typically means it goes into our 'To Do' bucket which becomes very dusty over time. Time to blow the dust away!
Dependency Injection in ASP.NET MVC (C#)
In this article, we are going to look at a little bit of the theory and then do a code walkthrough to understand basics of DI. By the end of the article, we should be clear about the pattern and how to apply Dependency Injection in an ASP.NET MVC application.
Dependency Injection is often associated with IoC (Inversion of Control) containers. We will not look at any IoC containers. We leave it for the next article in the series.
To get an idea of why we should adopt Dependency Injection (DI), we will first look at an abstract example without DI. Then we'll convert it into one with DI. Let us start off with a standard three-layer web application design. Figure 1 depicts a standard three-layer application.
The arrows above depict direction of coupling, as in the View layer is 'dependent' or 'has reference of' the Domain Layer and the Domain Layer is 'dependent' on the Data Access Layer. This is a common design where each layer represents a project in Visual studio.
On the outset, it looks a perfectly okay design approach. The way to use this would be the View layer code behind (or Controller classes in MVC) would instantiate a Domain Layer class and the domain layer would instantiate a Data access layer class and the calls from the View layer would get chained like this. Initially this seems harmless but programming against concrete instances actually makes our code very tightly coupled and highly 'dependent' on each other. Even though putting data access code separate from business logic code offers some immunity, it still does not give you any design benefit if in the future you had to change data sources say from a local source to a cloud source.
You will be forced to go and change declaration of every instance of the data access layer. In other words it is not a plug-in architecture.
Things get a little more complicated if you are using Data Access Entities (like the Entity Framework) and performing business manipulations on them. That would require the View layer to be 'aware' of these entities and hence refer to the Data Access Layer directly. The above diagram now becomes as follows:
Now this becomes a recipe for disaster because now you have lost control on Data Access and there is nothing stopping from the team newbie calling the data access layer directly and writing a loop in the code behind to manipulate data. Very soon you have your business logic all over the place and your seemingly well thought out layering has gone completely haywire.
Dependency Injection to the rescue
The term Dependency Injection, implies sending a dependency (DAL) into a dependent object (Domain Layer) as opposed to the dependent object controlling life cycle of its dependencies.
That would mean, that the domain layer should not instantiate the Data Access layer, the correct data access instance should be passed to it. Who will pass the instance? Is it the View layer? But does that mean View layer will instantiate the Data Access Layer? No. The View Layer will delegate the object instantiation to a special class called 'COMPOSITION ROOT'. The Composition Root will use configuration and a Factory to determine the correct instance. It will create an instance of the dependency (using reflection) and pass it into the View Layer. Since business layer is our glue between UI and persistence, it is okay to instantiate instance of Business layer directly in the view layer. To make the abstraction complete, the business logic layer should define an abstract class or interface for the Data Access layer to implement. This prevents code instantiation of data access layer anywhere in the Business or View layer. Our design diagram now changes to the following
Notice how the Domain Layer is no longer coupled to Data Access Layer in fact, the DAL now refers to the Domain Layer. This is because the Domain Layer defines the Interfaces that are implemented by the DAL Layer.
Okay, this resolves the dependency creation. But now how will the UI layer deal with data? Answer is 'Domain Objects'. The Domain layer will have to define Domain objects that are POCOs (Plain Old CLR Objects). The Repository implementation will translate the persistent entity Objects in DAL layer to Domain POCOs.
If you are ready to give up with the theory, hang in there for one more minute and we'll get to code.
Before we jump into code we should clarify one more term in DI, Constructor Injection. For DI to work, the dependencies need to be passed in to the dependent objects. The most common way to pass Dependencies is through constructor injection where in, all dependencies are pass as constructor parameters of the dependent objects. For example, in the above diagram, the composition root can pass instances of the Data Access layer only through the constructor of the Controllers (in View layer) and the View layer can pass that instance to the Domain layer only through the constructor of the Business Logic layer. This has an additional side effect i.e. we cannot use empty constructors for DI layers.
DI Code Walk Through
Okay, enough of theory let us see some code. In this post we will use a modified version of the SignalR application from earlier. The original Code does not use DI. In fact it’s not even split into three projects. Its layers are essentially split by Namespaces. We will take this code and convert it into a DI implementation.
Forking into Dependency Injection
I forked the existing code on my Hg repository so that I can save this branch and then do a fresh branch and Implement it using DI practices.
Step 1: Creating the Domain layer
To begin with, I am going to create the domain layer as follows:
1. Add Domain entities to interact with the View layer thus disconnecting View layer and data layer dependency.
Add reference to System.ComponentModel.DataAnnotations. Add a folder called Model and add a class called BlogPost.cs
The class looks like the following
2. Add a repository Interface to replace the coupling with Data Access layer. All data access calls will be made to the interface. The Interface has the following contract methods.
3. At this point our Domain layer is ready. We don’t really need to introduce any services because there isn’t any business logic that we are handling at the moment. So direct calls to the Repository will suffice. This is what our project looks like
Note: This is a highly simplified Domain layer. In a real life system you will have a service layer that will use an instance of the Repository passed from the View layer, get data from the repository and then pass back filtered/manipulated domain objects. Again, the service layer won’t be instantiating the Data Access layer, instead the DAL will be injected into it. The beauty of the Interface based design is you cannot even instantiate it, so there is no way for a developer to go astray. They are locked in to use constructor injection.
Step 2: Creating the Data Layer
Now we will build the Data Layer.
1. Add a new project called FunWithSignalR.Data
Add references to EntityFramework using Nuget command in the Package Manager Console
PM> Install-package EntityFramework
2. Add a folder Context and move BlogPostContext.cs from the FunWithSignalR.Models folder to this new folder.
3. Add a folder Model and move the BlogPost.cs from the FunWithSignalR.Models folder to this new folder.
Add a new method ToDomainBlogPost() that returns the Domain entity for the current Data entity. The ToDomainBlogPost() entity is a mapping method from a Data object to a Domain object.
The final code looks as follows
4. Add a folder Repository
Add the class SqlBlogPostRepository that implements IBlogPostRepository. The final implementation looks as follows. Note, for the Add and Update methods we are mapping the Domain object coming from View, into a Data object. Again in real life the mapping maybe more complex and data may
This completes the data layer implementation.
Step 3: The Composition Root
With the data layer and domain layer in place, first we’ll get the code to build and then we will then implement the dependency injection part. We will update the BlogPostController as follows:
1. Add a class level instance variable of type IBlogPostRepository
private IBlogPostRepository _repository;
2. Remove all instances of db context and replace them with appropriate repository method calls.
3. Build the solution. Interestingly enough, the solution will build correctly. But if we run it we’ll get a null reference exception for _repository because we have not instantiated with a concrete instance.
4. As discussed briefly earlier, the way to delegate responsibility is to pass the dependencies through constructor injection. The BlogPostController does not have a constructor so we will add one as follows:
5. As we can see above our controller now expects the _repository to be provided (injected with) a repository instance.
6. However the MVC Framework calls the BlogPostController and by default it expects an empty constructor. So how will we inject our dependency? MVC is a mind blowingly pluggable framework. You have to create a custom Controller Factory that derives from the DefaultControllerFactory. The class code is as follows
7. Let us look at the factory class closely
a. It has a dictionary for storing the controllers.
b. The constructor is still taking a parameter of type repository (so we will be injecting the dependency into the controller factory as well).
c. The constructor has a ‘guard method’ to ensure that repository parameter is not null.
d. It then initializes the controller map and adds the two controllers that we have Home and Blog.
e. We next override the CreateController method to return correct controller based on the controllerName and requestContext.
8. With the BlogControllerFactory in place we have ironed out the Constructor injection for the MVC controller. All that is remaining is creation of the CompositionRoot and hooking it up with the application start
a. The CompositionRoot class can be just called so. Add it to the root of the FunWithSignalR project. You could create a new project or folder for it too, but doesn’t really matter.
b. The implementation of the CompositionRoot class is simple. The code listing is as follows
c. There is a local instance variable of the controllerFactory of type IControllerFactory
d. The constructor is public and without parameters. It calls a private static method CreateControllerFactory().
e. The CreateControllerFactory() method is where our dependency instantiation happens.
-
It picks up the Type name from web.config ‘s AppSettings section.
-
Gets the Type by name
-
Builds an instance using Activator.CreateInstance. Notice how we don’t know the instance type at any point because the CompositionRoot is only aware of the Interface. So we cast the instance back as the interface only.
-
This instance is used to instantiate the BlogContollerFactory
-
Returns the BlogControllerFactory to the constructor, that’s saved in the local controllerFactory variable.
f. Update the web.config and add the type name
9. Now all that remains is using the CompositionRoot and letting MVC know that it should use our ControllerFactory instead of the default one. We do this in the Application_Start() event as follows
We initialize the Composition Root. We get the Current ControllerBuilder (provided by the MVC framework) and call the SetControllerFactory method by passing the ControllerFactory from the composition root.
10. Update all the Blog Views to refer to FunWithSignalR.Domain.Model.BlogPost instead of FunWithSignalR.Models.BlogPost.
11. Finally, remember the View layer doesn’t have access to the Data Layer. It uses reflection to generate the dependency, so the Data layer dll must be available as a part of the build. To make that happen add a build event for the solution that copies over the FunWithSignalR.Data.dll over to the View’s bin folder. The command is as follows.
copy "$(SolutionDir)FunWithSignalR.Data\bin\$(ConfigurationName)\*.dll" "$(TargetDir)"
12. I have not included the contents of the packages folder (reduce download size). Instead you will see a .nuget folder with a .targets file. Basically I have enabled “Nuget Package Restore”. Now at Nuget can download required packages at build time. If you are using Visual Web Dev Express, on load you will get a warning saying Solution folders are not supported and you won’t see the .nuget folder in your solution explorer, however the build targets will continue to work.
This completes our wiring up of our entire application.
Dependency Injection - Recap
- Dependency Injection is a Design pattern that enables us to write loosely coupled code (Ref: Dependency Inject in .NET By Mark Seemann) and enforces, dependent object give up control of managing their dependencies and instead let a Composition Root inject the dependencies into them.
- Using a Composition Root in a manner described above is often referred to as ‘Poor man’s DI’ pattern. This is not so much of a bad thing as it is an indicator of lack of Inversion of Control Containers. IoC Containers help in taking away the pain of registering each new object and managing their instances. Some common IoC containers for .NET are Castle Windsor, Unity, Ninject. We will discuss IoC containers in one of our future article.
- DI + Repository + Programming against Interfaces overall help in separation of concerns and greatly improves the overall application maintainability.
- The above design has zero impact on change to View or Data layer.
-
For example, if we were to introduce a new Mobile view we could simply go and build it from scratch while using the exact same Domain and Data Access Layer. All we had to do was ensure the dependencies are created correctly at the Composition Root.
-
Similarly to swap the Sql backend with an Azure backend there would be zero impact on the business layer or the View layer. All that would change was the configuration information providing the concrete type for the Azure repository implementation.
-
In any other design the impact of such changes is much more pervasive and requires touching all layers of an application.
Conclusion
Taking a little bit of time to learn about design patterns prepare us to better recognize practical scenarios of application. Dependency Injection in my book is one of the most important patterns for a seasoned ASP.NET MVC developer. It helps layout a truly flexible, decoupled foundation for what seems a simple problem but will most certainly become a very complex application in future.
The entire source code of this article can be downloaded over here
References
1. Dependency Injection in .NET by Mark Seemann – A must read for .NET Devs
2. Principles of Object Oriented Design by Robert C. Martin (Uncle Bob)
3. Getting a SOLID Start by Uncle Bob.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Sumit is a .NET consultant and has been working on Microsoft Technologies since his college days. He edits, he codes and he manages content when at work. C# is his first love, but he is often seen flirting with Java and Objective C. You can follow him on twitter at @
sumitkm or email him at sumitkm [at] gmail