ASP.NET Core Dependency Injection

ASP.NET Core Dependency Injection with Example

In this article, I will discuss ASP.NET Core Dependency Injection with Examples. Please read our previous article before proceeding to this one, where we discussed ASP.NET Core MVC Views with Examples. The Dependency Injection Design Pattern is one of the most used design Patterns in Real-Time Applications. The good thing is that ASP.NET Core provides built-in support for dependency injection. As part of this article, we will discuss the following pointers in detail.

  1. Understanding the Need for ASP.NET Core Dependency Injection
  2. What is the Dependency Injection Design Pattern?
  3. How do you Register a Service with ASP.NET Core Dependency Injection Container?
  4. What are the different Methods ASP.NET Core Provides to Register a Service?
  5. Understanding the Singleton, Scoped, and Transient Methods
  6. What are the Advantages of using Dependency Injection?
Understanding the Need for ASP.NET Core Dependency Injection

Let us understand the need for Dependency Injection Design Patterns in ASP.NET Core Applications with an example. First, create a new ASP.NET Core Application named FirstCoreMVCWebApplication with an Empty Project Template. To create a new Empty ASP.NET Core Web Application, open Visual Studio 2022 and click the Create a new project tab, as shown in the image below.

Creating a new ASP.NET Core Empty Application

Once you click on the Create a new project tab, it will open the Create a new project window. You need to select the ASP.NET Core Empty project template from this window and click the Next button, as shown in the image below.

Creating a new ASP.NET Core Empty Application

Once you click on the Next button, it will open the Configure Your New Project window. Here, you must provide the necessary information to create a new project. First, give an appropriate name for your project (FirstCoreMVCWebApplication), set the location where you want to create this project, and the solution name for the ASP.NET Core Web application. And finally, click on the Create button, as shown in the image below.

How to Set up MVC in ASP.NET Core Application

Once you click on the Next button, the Additional Information window will open. You must select .NET 6.0 as the Framework, check the Configure for HTTPS and do not use top-level statements check boxes, and finally click on the Create button, as shown in the image below.

How to Set up MVC in ASP.NET Core Application

That’s it. Once you click the Create Button, the project will be created with the Empty template with the following folder and file structure.

How to Set up MVC in ASP.NET Core Application

Adding Models:

Once you created the ASP.NET Core Empty Project, let’s add our models. To do so, first, create a folder with the name Models. Within the Models folder, let us add a class file with the name Student.cs, and this Student class will be our model for this application. Then open the Student.cs class file and copy and paste the following code into it.

namespace FirstCoreMVCWebApplication.Models
{
    public class Student
    {
        public int StudentId { get; set; }
        public string? Name { get; set; }
        public string? Branch { get; set; }
        public string? Section { get; set; }
        public string? Gender { get; set; }
    }
}
Creating Service Interface:

Next, create an interface named IStudentRepository.cs within the Models folder. This interface will declare the list of methods or operations we can perform on the student data. So, open IStudentRepository.cs and copy and paste the following code. Here, you can see we have created the interface with two methods.

using System.Collections.Generic;
namespace FirstCoreMVCWebApplication.Models
{
    public interface IStudentRepository
    {
        Student GetStudentById(int StudentId);
        List<Student> GetAllStudent();
    }
}
Creating Service Implementation:

Next, create a class file named StudentRepository.cs within the same Models folder. Then open the StudentRepository.cs class file and copy-paste the following code. This class implements the IStudentRepository interface by implementing the two methods declared in the IStudentRepository interface. Here, we have hard-coded the student data, but you will get the student data from a database in real-time applications.

using System.Collections.Generic;
using System.Linq;

namespace FirstCoreMVCWebApplication.Models
{
    public class StudentRepository : IStudentRepository
    {
        public List<Student> DataSource()
        {
            return new List<Student>()
            {
                new Student() { StudentId = 101, Name = "James", Branch = "CSE", Section = "A", Gender = "Male" },
                new Student() { StudentId = 102, Name = "Smith", Branch = "ETC", Section = "B", Gender = "Male" },
                new Student() { StudentId = 103, Name = "David", Branch = "CSE", Section = "A", Gender = "Male" },
                new Student() { StudentId = 104, Name = "Sara", Branch = "CSE", Section = "A", Gender = "Female" },
                new Student() { StudentId = 105, Name = "Pam", Branch = "ETC", Section = "B", Gender = "Female" }
            };
        }

        public Student GetStudentById(int StudentId)
        {
            return DataSource().FirstOrDefault(e => e.StudentId == StudentId) ?? new Student();
        }

        public List<Student> GetAllStudent()
        {
            return DataSource();
        }
    }
}
Program.cs:

In the Program class, we need to do two things. First, we need to configure the required MVC service to the IoC Container, and then we need to add the MVC Middleware to the request processing pipeline. So, modify the Program class as shown below.

namespace FirstCoreMVCWebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add MVC services to the container.
            builder.Services.AddMvc();

            var app = builder.Build();

            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                //Configuring the MVC middleware to the request processing pipeline
                endpoints.MapDefaultControllerRoute();
            });

            app.Run();
        }
    }
}
Without Dependency Injection:

Create a folder named Controllers in your project. Then, add a class file named HomeController.cs within the Controllers folder. Then open the HomeController.cs file and copy-paste the following code into it. Here, you can see that within the Index and GetStudentDetails action methods, we are creating an instance of the StudentRepository class and calling the respective methods.

using FirstCoreMVCWebApplication.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace FirstCoreMVCWebApplication.Controllers
{
    public class HomeController : Controller
    {
        public JsonResult Index()
        {
            StudentRepository repository = new StudentRepository();
            List<Student> allStudentDetails = repository.GetAllStudent();
            return Json(allStudentDetails);
        }

        public JsonResult GetStudentDetails(int Id)
        {
            StudentRepository repository = new StudentRepository();
            Student studentDetails = repository.GetStudentById(Id);
            return Json(studentDetails);
        }
    }
}

With the above changes in place, now run the application and check the above two methods. it should work as expected, as shown in the image below.

What is the Problem in the above implementation?

Let us first understand the problem in the above implementation. Then, we will discuss how we can overcome it by using the Dependency Injection Design Pattern in the ASP.NET Core application.

What is the Problem with the above implementation?

As you can see in the above HomeController class, the HomeController class depends on an instance of the StudentRepository class to get student data. Here, within the HomeController class, we create an instance of the StudentRepository class and then invoke the GetStudentById() and GetAllStudent methods as per our requirement. This is tight coupling because the HomeController class is now tightly coupled with the StudentRepository concrete class.

Tomorrow, if the implementation class of the IStudentRepository is changed from StudentRepository to TestStudentRepository, then we also need to make the changes to the code in the HomeController class, as they are both tightly coupled. We can overcome this problem by implementing the Dependency Injection Design Pattern.

What is the Dependency Injection (DI) Design Pattern?

Dependency Injection is the process of injecting the dependency object into a class that depends on it. It is the most commonly used design pattern nowadays to remove the dependencies between objects, allowing us to develop loosely coupled software components. Let us discuss the step-by-step procedure of how to implement dependency injection in the ASP.NET Core MVC application.

The ASP.NET Core Framework is designed from scratch to provide inbuilt support for Dependency Injection Design Patterns. The ASP.NET Core Framework injects the dependency objects to a class through a constructor or method using the built-in IoC (Inversion of Control) container.

The built-in IoC (Inversion of Control) container is represented by IServiceProvider implementation, which supports default constructor injection. The types (i.e., classes) managed by built-in IoC containers are called services.

Types of Services in ASP.NET Core:

There are two types of services in ASP.NET Core. They are as follows:

  1. Framework Services: Services that are a part of the ASP.NET Core Framework, such as IApplicationBuilder, IHostingEnvironment, ILoggerFactory, etc.
  2. Application Services: The services (custom types or classes) you create as a programmer for your application.

To let the IoC container automatically inject our application services, we must first register them with the IoC container.

How do you Register a Service with ASP.NET Core Dependency Injection Container?

We need to register a service with the ASP.NET Core Dependency Injection Container within the Main method of the Program class. Before we discuss how to Register a service with the Dependency Injection Container, it is important to understand the service’s lifetime. Setting the lifetime of the dependency object determines how many times it needs to be created.

What are the Different Methods ASP.NET Core Provides to Register a Service with the Dependency Injection Container?

ASP.NET Core provides 3 methods for registering a service with the ASP.NET Core Dependency Injection container. The method we use to register a service will determine its lifetime.

Singleton:

A Singleton service is created only once per application lifetime. The same instance is used throughout the application. It is ideal for stateless services or maintaining a consistent state throughout the application’s lifetime. Common uses include configuration services, logging, or other services where a single instance is sufficient and desirable. This can be achieved by adding the service as a singleton through the AddSingleton method of the IServiceCollection.

Transient:

A Transient service is created each time it is requested from the service container. This means a new instance is provided to every class or method that requires it. This is ideal for lightweight, stateless services. Since a new instance is always created, you don’t need to worry about thread safety related to the internal state. This can be achieved by adding the service through the AddTransient method of the IServiceCollection.

Scoped:

A Scoped service is created once per client request (in a web application, this typically means per HTTP request). This is ideal for services that need to maintain state within a single request but should not be shared across different requests. Common examples include data access operations within a single transaction. This can be achieved by adding the service through the AddScoped method of the IServiceCollection.

Registering the StudentRepository with ASP.NET Core Dependency Injection 

We need to register the service to the built-in dependency injection container with the program class. The following code shows how to register a service with different lifetimes:

Registering the StudentRepository Object

What is the ServiceDescriptor class in .NET Core?

The ServiceDescriptor class is part of the Dependency Injection (DI) framework provided by Microsoft in the ASP.NET Core framework. It essentially describes how a service should be instantiated and managed by the container. So, it describes a service, including its lifetime (singleton, scoped, or transient), the service type, and the implementation type.

Extension Methods for Registration

ASP.NET Core framework includes extension methods for each type of lifetime: AddSingleton(), AddTransient(), and AddScoped() methods for singleton, transient, and scoped lifetime, respectively. The following example shows how to register types (services) using extension methods.

Extension Methods for Registration

Let us use the service’s Singleton Instance in this example. Modify the Main method of the Program class as shown below. Which approach do you want to use to register the service? It is your preference.

using FirstCoreMVCWebApplication.Models;

namespace FirstCoreMVCWebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add Framework MVC services to the Container.
            builder.Services.AddMvc();

            //Application Service
            builder.Services.AddSingleton<IStudentRepository, StudentRepository>();
            //builder.Services.AddSingleton(typeof(IStudentRepository), typeof(StudentRepository));
            //builder.Services.AddTransient<IStudentRepository, StudentRepository>();
            //builder.Services.AddTransient(typeof(IStudentRepository), typeof(StudentRepository));
            //builder.Services.AddScoped<IStudentRepository, StudentRepository>();
            //builder.Services.AddScoped(typeof(IStudentRepository), typeof(StudentRepository));

            //Add Application Service to the Container.
            //builder.Services.Add(new ServiceDescriptor(typeof(IStudentRepository),
            //    new StudentRepository())); // by default singleton
            //builder.Services.Add(new ServiceDescriptor(typeof(IStudentRepository),
            //    typeof(StudentRepository), ServiceLifetime.Singleton)); // singleton
            //builder.Services.Add(new ServiceDescriptor(typeof(IStudentRepository),
            //    typeof(StudentRepository), ServiceLifetime.Transient)); // Transient
            //builder.Services.Add(new ServiceDescriptor(typeof(IStudentRepository),
            //    typeof(StudentRepository), ServiceLifetime.Scoped));    // Scoped

            var app = builder.Build();

            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                //Configuring the MVC middleware to the request processing pipeline
                endpoints.MapDefaultControllerRoute();
            });

            app.Run();
        }
    }
}
Constructor Injection in ASP.NET Core MVC Application

Once we register the service, the IoC container automatically performs constructor injection if a service type is included as a parameter in a constructor. Let us modify the HomeController, as shown below, to use Constructor Dependency Injection in the ASP.NET Core MVC Application.

using FirstCoreMVCWebApplication.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace FirstCoreMVCWebApplication.Controllers
{
    public class HomeController : Controller
    {
        //Create a reference variable of IStudentRepository
        private readonly IStudentRepository? _repository = null;

        //Initialize the variable through constructor
        public HomeController(IStudentRepository repository)
        {
            _repository = repository;
        }

        public JsonResult Index()
        {
            List<Student>? allStudentDetails = _repository?.GetAllStudent();
            return Json(allStudentDetails);
        }

        public JsonResult GetStudentDetails(int Id)
        {
            Student? studentDetails = _repository?.GetStudentById(Id);
            return Json(studentDetails);
        }
    }
}
Code Explanation:

In the above example, the IoC container will automatically inject an instance of the StudentRepository into the constructor of HomeController. We don’t need to do anything else. An IoC container will create and dispose of an instance of the IStudentRepository based on the registered lifetime. Injecting the dependency object through a constructor is called a constructor dependency injection.

We created the _ repository variable as read-only, ensuring that once we inject the dependency object, that value can never be changed. At this point, run the application, and you should get the output as expected, as shown in the below image.

Constructor Injection in ASP.NET Core MVC Application

Action Method Injection in ASP.NET Core Application

Sometimes, we only need a dependency object in a single action method. In that case, we need to use the [FromServices] attribute. For a better understanding, please modify the HomeController class as follows. Here, you can see we are using the [FromServices] attribute within the Index action method. So, at runtime, the IoC Container will inject the dependency object into the IStudentRepository repository reference variable. Injecting the dependency object through a method is called method dependency injection.

using FirstCoreMVCWebApplication.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace FirstCoreMVCWebApplication.Controllers
{
    public class HomeController : Controller
    {
        public JsonResult Index([FromServices] IStudentRepository repository)
        {
            List<Student> allStudentDetails = repository.GetAllStudent();
            return Json(allStudentDetails);
        }
    }
}

Run the application, and you will get the expected output, as shown below.

Action Method Injection in ASP.NET Core Application

What is FromServices Attribute in ASP.NET Core?

The FromServices Attribute in ASP.NET Core is a way to perform dependency injection directly into controllers’ action methods. Instead of injecting dependencies through the controller’s constructor, you can use this attribute to inject them directly into an action method. This is useful when a specific service is needed only in a single action method and not throughout the controller.

Property Dependency Injection in ASP.NET Core

The Built-in IoC container does not support property injection. You will have to use a third-party IoC container.

Get Services Manually in ASP.NET Core

We can also manually access the services configured with built-in IoC containers using the RequestServices property of HttpContext. So, modify the HomeController class as shown below to access the dependent service manually.

using FirstCoreMVCWebApplication.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace FirstCoreMVCWebApplication.Controllers
{
    public class HomeController : Controller
    {
        public JsonResult Index()
        {
            var services = this.HttpContext.RequestServices;
           
            IStudentRepository? _repository = (IStudentRepository?)services.GetService(typeof(IStudentRepository));
            List<Student>? allStudentDetails = _repository?.GetAllStudent();
            return Json(allStudentDetails);
        }

        public JsonResult GetStudentDetails(int Id)
        {
            var services = this.HttpContext.RequestServices;
            IStudentRepository? _repository = (IStudentRepository?)services.GetService(typeof(IStudentRepository));
            Student? studentDetails = _repository?.GetStudentById(Id);
            return Json(studentDetails);
        }
    }
}

With the above changes in place, run the application, and you should get the output as expected as in the previous examples. It is recommended to use constructor injection instead of getting it using RequestServices.

What is the GetService Method in ASP.NET Core?

The GetService method in ASP.NET Core is a part of the dependency injection (DI) system provided by the framework. It is used to retrieve a service instance from the DI container. You need to pass the type of service you want to retrieve as a parameter to this method.

What are the Advantages of using ASP.NET Core Dependency Injection?

The ASP.NET Core Dependency Injection allows us to develop loosely coupled software components. Here are some of the advantages of using dependency injection in ASP.NET Core:

  1. Loose Coupling: By using dependency injection, we can separate our classes from their dependencies, resulting in code that is simpler to maintain and test.
  2. Testability: By using dependency injection, we can increase the testability of our code by easily replacing dependencies with mock objects during unit testing.
  3. Extensibility: Using Dependency injection enhances the extensibility of our code by offering the flexibility to switch out dependencies conveniently.
  4. Reusability: Using dependency injection makes our code more reusable since we can conveniently share dependencies among various classes.

In the next article, I will discuss Singleton vs. Scoped vs. Transient Services in ASP.NET Core Application with Examples. In this article, I try to explain the ASP.NET Core Dependency Injection with examples. I hope this article will help you understand the Dependency Injection Concept in ASP.NET Core MVC Applications. 

11 thoughts on “ASP.NET Core Dependency Injection”

  1. blank

    Finally a clear and educational tutorial as I needed to assimilate this notion. Thank you very much and well done

  2. blank

    Setting the lifetime of the dependency object determines how many times the dependency object needs to be created.

    refer above sentence it i from your blog of “https://dotnettutorials.net/lesson/asp-net-core-dependency-injection” page

    this many time or much time?
    Please confirm

Leave a Reply

Your email address will not be published. Required fields are marked *