Understanding Dependency Injection in ASP.Net MVC applications
In this post I am going to discuss Dependency Injection pattern, explain why we need it and how to use it in our modern web applications based on ASP.Net MVC paradigm.
DI (Dependency Injection) is not a difficult concept to grasp but a lot of developers do not understand it or even worse they use it wrongly.
We use DI to decouple layers in our application. I assume that you use Layered Architecture principles and patterns when architecting your application.
Usually we want to decouple the Domain's Layer dependency on the Persistence Layer. Have a look at the picture below.
It is obvious why we would like something like that. At the moment I utilise Entity Framework and SQL Server in my application but later on a new specification comes in which dictates that we should switch NHibernate and Oracle.
So at the end of the day as Solution Architects we need to decouple those two layers.
To utilise DI, or better if we intend to use DI in our project we need first to add a layer of abstraction between those two layers. This level of abstraction comes in the form of an Interface (a C# Interface if you want).
The Domain layer can talk to any persistence layer as long as this Persistence layer implements the methods defined in the contract (interface).
By doing that it is quite obvious that both the Domain Layer and the Persistence Layer both rely / depend on an abstraction.
No longer the Domain Layer needs to create new instances of concrete classes in the Persistence Layer, the coupling between those two layers does not exist and the dependency is broken.
The Persistence Layer implements the abstraction, in our case the C# interface.
So at runtime, some third party, can inject an instance of the Persistence Layer in the Domain Layer dynamically.
Have a look at the picture below.
When talking, understanding the DI pattern we need to understand the Dependency Inversion Principle.
This principle merely states that High level modules (classes) should not depend on Low level modules (classes), both should depend on abstractions.
Abstractions should not depend on details, details should depend upon abstractions.
Another principle we should bear in mind when talking about DI is the Inversion of Control Principle.
IoC states that a third party injector , or a third party container controls the flow of the program and determines which objects should be created and where they should be passed.
In DI there is a consumer that depends on the other classes for some service. Then there is a declaration of that consumer's (consumer = a certain class) need in the form of a contract/interface.
Finally there is a third-party injector,provider,container that supplies instances of classes that adhere to the contract to the dependent consumer classes.
This third-party injector software is best known as a DI Container. There are many DI Containers, most of them open- source, that developers use nowadays.
Unity, Ninject, Autofac are the most widely used DI containers.
These DI containers know which concrete classes to pass to the dependent consumer classes. We need to configure this information in a configuration file e.g XML file or in a C# code class.
Basically we create mappings in this C# code class, whenever you see this interface pass me an instance of this particular class.
In our consumer classes we need to enable/allow for an injected implementation.
The way I do it, or most people I know do it, is by using Constructor Injection.
Have a look at the code below.
public class OrderService
{
private readonly IOrderRepository _orderRepository;
public OrderService(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
//more code goes here
}
In our class, in our constructor it takes an instance of the IOrderRepository and in the body of that constructor it saves an instance to a local pivate read only field.
I am going to create an ASP.Net Core application to demonstrate DI.
I have installed Visual Studio 2015 Enterprise in my machine and have downloaded .Net Core. You can download Visual Studio 2015 Community edition.
In ASP.Net Core DI is a first class citizen and there is native support for it.
1) Launch Visual Studio 2015 and start a new ΑSP.Net Core Web Application.Give it an appropriate name.
2) Add a folder Models in the project. Add a class that describes a department
public class Department
{
public string Name { get; set; }
public decimal Budget { get; set; }
public DateTime StartDate { get; set; }
}
3) Create a folder Interfaces in the project. Add this code below in it
public interface IDepartmentRepository
{
List<Department> GetAll();
}
This is a simple method that we need to implement in the concrete class.
4) Add a folder Repositories.Add the following code in it. We just implement the GetAll method which just populates with data the Deparment in memory object.
public class DepartmentRepository:IDepartmentRepository
{
public List<Department> GetAll()
{
return new List<Department>()
{
new Department()
{
Name = "Physics",
Budget = 250000,
StartDate=DateTime.Parse("12/12/1999")
},
new Department()
{
Name = "Maths",
Budget = 550000,
StartDate=DateTime.Parse("11/11/1981")
},
new Department()
{
Name = "Software",
Budget = 950000,
StartDate=DateTime.Parse("08/11/1987")
}
};
}
}
5) In the Controllers folder in the HomeController.cs comment out everything. The new code follows.
public class HomeController : Controller
{
private readonly IDepartmentRepository _depRepo;
public HomeController(DepartmentRepository depRepo)
{
_depRepo = depRepo;
}
public IActionResult Index()
{
return View(_depRepo.GetAll());
}
}
We have a pivate readonly instance of our interface IDepartmentRepository and the constructor takes an instance DepartmentRepository. This is constructor injection.
6) Τhe Startup.cs configures the environment which our app will run. The Startup.cs file also places services into ASP.Net Core's Services layer,which is what enables dependency injecction.
I add the following line in bold.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
services.AddTransient<DepartmentRepository>();
}
7) Build and run your application. You will see the list with the departments.
In DI we have the concept of "lifetimes". A lifetime specifies when a DI-injected object gets created or recreated. There are three options:
Transient: Created each time they are requested.
Scoped: Created once per request.
Singleton: Created the first time they are requested. Each subsequent request uses the instance that was created the first time.
To recap when talking about the DI pattern we need to understand the Dependency Inversion Principle and the Inversion of Control Principle.
DI is a very useful pattern when we need to decouple Layer's functionality, thus making our application more maintainable.
Hope it helps!!!