Dependency injection has now become the first class citizen in ASP.NET Core. It helps us to build loosely coupled, easily readable and maintainable code. In this tutorial, we will learn the basics of the dependency injection by building a simple application.
Table of Contents
Introduction to dependency injection in ASP.NET Core
The Dependency injection is now part of the ASP.NET Core. All the Framework services are now injected as services wherever you need them.
But before going further, we need to understand why dependency injection is needed in the first place.
Consider the following controller action method. Which gets the list of products from the ProductService.
1 2 3 4 5 6 7 8 9 10 | public class HomeController : Controller { public IActionResult Index() { _productService = new ProductService(); return View(_productService.getAll()); } } |
The Index action method has a dependency on the ProductService. Hence it creates an instance of it and invokes its getAll method to get a list of Products.
The ProductService is now tightly coupled to the Index Action method of the HomeController class.
What if we created a betterProductService and wanted to replace the old ProductService with the betterProductService.
1 2 3 4 5 6 7 | public IActionResult Index() { _productService = new BetterProductService(); return View(_productService.getAll()); } |
We need to do this in every controller, service, where we used ProductService.
What if we wanted to use testProductService and wanted to use it only in the testing and use the productService in the Production. No easy solution here.
Consider the case where ProductService depends on another service, which depends on yet another service. It is not uncommon that such a chain of dependencies to exist in our application.
The Dependency Injection system solves all these problems.
What is dependency injection
Dependency injection (also known as DI) is a design pattern in which an object does not create it dependent classes, but asks for it.
Let’s change our HomeController a bit.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class HomeController : Controller { private IProductService _productService; public HomeController(IProductService productService) { _productService = productService; } public IActionResult Index() { return View(_productService.All()); } } |
The difference between the above code and here is that we are not creating the instance of ProductService in the Index action method. We are asking for it in the constructor of the HomeController.
The problem is still not solved right?. Someone has to create the instance of the ProductService and pass it to the HomeController.
This is where the ASP.NET Cores Dependency injection framework comes in. The Responsibility of creating the ProductService is now rests with the framework. The object that does this is called DI Container or Ioc Container.
Dependency injection is a design pattern. Dependency injection framework implements that design pattern. There are many frameworks are available like Autofac, Unity etc. which you can use with the ASP.NET Core.
DI Container
DI Container is the object, which is responsible for creating the dependencies (productService) and pass it to the object that requests (HomeController) it.
How does DI Container know which object create?
We need to configure DI Container with the classes that you want to participate in dependency injection. This we do it in the startup class under the ConfigureServices method as shown below.
1 2 3 4 5 6 7 | public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddTransient<IProductService, ProductService>(); } |
The second line of code registers the ProductService to the service collection using the method AddTransient. The other two methods available are AddSingleton & AddScoped. The three methods define the lifetime of the services. We will discuss this in the next tutorial.
Example of Dependency Injection System
Create an ASP.NET Core project using the empty template and name it DependencyInjection. Add the HomeController with index method. You can follow these tutorials
Creating the View Model
Create the Models folder and create the following viewModel.
1 2 3 4 5 6 7 | public class ProductViewModel { public int Id { get; set; } public string Name { get; internal set; } } |
Adding the Service
Create the folder Services and add a class with the name ProductService.cs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | using DependencyInjection.Models; using System.Collections.Generic; namespace DependencyInjection.Service { public interface IProductService { List<ProductViewModel> getAll(); } public class ProductService : IProductService { public List<ProductViewModel> getAll() { return new List<ProductViewModel> { new ProductViewModel {Id = 1, Name = "Pen Drive" }, new ProductViewModel {Id = 2, Name = "Memory Card" }, new ProductViewModel {Id = 3, Name = "Mobile Phone" }, new ProductViewModel {Id = 4, Name = "Tablet" }, new ProductViewModel {Id = 5, Name = "Desktop PC" } , }; } } } |
First, we added the IProductService interface, and then ProductService which implements that Interface.
The ProductService returns the list of Products. The Product List is hardcoded into the service. In real life, you go into the database to fetch the product List.
Using the Service in Controller
Next, Open the HomeController and add the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | using DependencyInjection.Service; using Microsoft.AspNetCore.Mvc; namespace DependencyInjection.Controllers { public class HomeController : Controller { private IProductService _productService; public HomeController(IProductService productService) { _productService = productService; } public IActionResult Index() { return View(_productService.getAll()); } } } |
The constructor of the HomeController asks for ProductService and stores the instance in local variable _productService.
The index method calls the view with the list of products by invoking the getAll method.
View
The View just displays the list of Products as shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @model List<DependencyInjection.Models.ProductViewModel>; @{ ViewData["Title"] = "Index"; } <h2>Index</h2> @foreach (var product in Model) { <p>@product.Id @product.Name</p> } |
Register the Service
The last step is to register the service in the Dependency Injection container.
Open the startup.cs and goto to ConfigureServices method. This is where all services are configured for dependency injection.
1 2 3 4 5 6 7 | public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddTransient<IProductService, ProductService>(); } |
We have registered the ProductService using the AddTransient method. The other method available is AddScoped & AddSingleton. You will learn about these methods in Dependency Injection Lifetime: Transient, Singleton & Scoped tutorial
Now, run the application and you should be able to see the list of products.
How Dependencies are injected
The following image shows how ProductService was injected into the HomeController.

When the new HomeController is requested, the MVC asks the Dependency injection framework to provide an instance of the HomeController class. The DI Container inspects the constructor of the HomeController and determines its dependencies. It then searches for the dependencies in the services registered in the service collection and finds the matching service and creates an instance of it. Then it creates the HomeController and passes the dependencies in its constructor.
Creating the BetterProductService
Now, let us build another service called BetterProductService and want to use this service instead of the ProductService.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class BetterProductService : IProductService { public List<ProductViewModel> getAll() { return new List<ProductViewModel> { new ProductViewModel {Id = 1, Name = "Television" }, new ProductViewModel {Id = 2, Name = "Refrigerator" }, new ProductViewModel {Id = 3, Name = "IPhone" }, new ProductViewModel {Id = 4, Name = "Laptop" }, }; } } |
All you have to do is to go to ConfigureServices and change the ProductService to BetterProductService.
1 2 3 4 5 6 7 8 | public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddTransient<IProductService, BetterProductService>(); } |
You do not have to go to each controller & services and change the reference. You can manage it from one central location.
Similarly, you can create the TestProductService use it for testing
Changing the service based on the environment
For Example, you can use the environment and switch between the various services as shown below.
In the constructor of the startup class, ask for IHostingEnvironment service as shown below.
1 2 3 4 5 6 7 | IHostingEnvironment _env; public Startup(IHostingEnvironment env) { _env = env; } |
Next, in the configureServices check the environment. The following code configures the BetterProductService in Production and ProductService in all other environments.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public void ConfigureServices(IServiceCollection services) { services.AddMvc(); if (_env.IsProduction()) { services.AddTransient<IProductService, BetterProductService>(); } else { services.AddTransient<IProductService, ProductService>(); } } |
To change the environment select the Project, Right click and go to properties. Select the debug tab. Change the ASPNETCORE_ENVIRONMENT to whatever you want it to be.
Constructor Injection vs Action injection
You can inject the services in the controller in two ways.
- Construction Injection
- Action Injection
Constructor Injection
When the dependency is injected through the constructor then the method is known as constructor injection.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class HomeController : Controller { private IProductService _productService; public HomeController(IProductService productService) { _productService = productService; } public IActionResult Index() { return View(_productService.All()); } } |
Action Injection
If the dependencies are injected to an action method, then the method is known as Action Injection.
The Action Injection is done using the [FromServices] attribute to an argument in an action method as shown below. Use this method, if the service is used only in a single action method.
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class HomeController : Controller { public HomeController() { } public IActionResult Index( [FromServices] IProductService productService) { return View(_productService.All()); } } |
Benefits of Dependency injection
- Dependency injection facilitates loose coupling of software components
- The Code is clean and more readable
- Improves the testability and maintainability of the applications
- Allows you to change your implementations without having to change the classes
Summary
In this tutorial, we learned the basics of the ASP.NET Core dependency injection system. In the next tutorial, we learn how to manage the lifetime of the services using AddTransient, AddSingleton & AddScoped.



Greate article, very clear!
What if you don’t inject the dependency? Is it null or is an error thrown?
This is really awesome, and everything is explained very well. Thanks.
I have read a lot of articles, but I understand the topic from this article, thank you very very much
thanks my basic knowledge is more clear.
Thanks, Suraj
—————————–
…
Let’s change our HomeController a bit.
public class HomeController : Controller
{
private IProductService _productService;
public HomeController(IProductService productService)
{
_productService = productService;
}
public IActionResult Index()
{
_productService = new ProductService(); <<<<<<<<<<<<<<<<<<<<
return View(_productService.All());
}
}
The difference between the above code and here is that
we are not creating the instance of ProductService in the Index action method. <<<<<<<<<<<<<<<<
We are asking for it in the constructor of the HomeController.
…..
———————————–
yes, you DO creating…
Thanks for the correction.