ASP.NET Core Dependency Injection

ASP.NET Core Dependency Injection with Example

In this article, I am going to discuss the ASP.NET Core Dependency Injection with an example. Please read our previous article before proceeding to this article where we discussed Models in ASP.NET Core MVC application. The Dependency Injection Design Pattern is one of the most used design Patterns in real-time applications. But the good thing is that ASP.NET Core Provides inbuilt support for Dependency Injection. As part of this article, we are going to discuss the following pointers in details.

  1. Understanding the need for ASP.NET Core Dependency Injection
  2. What is Dependency Injection?
  3. How to register a Service with ASP.NET Core Dependency Injection Container?
  4. What are the different methods ASP.NET Core Provides to register a service with Dependency Injection Contains?
  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 in ASP.NET Core Application with an example. First, create a new ASP.NET Core Application with the name “FirstCoreMVCWebApplication” with Empty project template.

Adding Models:

Once you created the Project with the Empty Project template, then let’s add our models to our application. 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 is going to be our model for this application. Then open the Student.cs class file and copy and paste the following code in 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:

Then create an interface with the name IStudentRepository.cs within the Models folder. This interface is going to declare the list of methods that we can perform on the student data. So, open IStudentRepository.cs and then copy and paste the following code in it.

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

Create a class file with the name TestStudentRepository.cs within the same Models folder. Then open the TestStudentRepository.cs file and copy-paste the following code in it. This class implements the IStudentRepository interface by providing the implementation of the two methods declared in that interface.

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

namespace FirstCoreMVCWebApplication.Models
{
    public class TestStudentRepository : 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);
        }

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

In the Startup class initially, 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 Startup class as shown below.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace FirstCoreMVCWebApplication
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
            });
        }
    }
}
Without Dependency Injection:

Create a folder with the name Controllers in your project. Then add a class file with the name HomeController.cs within the Controllers folder. Then open the HomeController.cs file and copy-paste the following code in it.

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

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

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

With the above changes in place, now run the application and check the above two methods and it should work as expected. Let us first understand what is the problem in the above implementation and how we can overcome this by using the dependency injection design pattern in the ASP.NET Core application.

What is the Problem in the above implementation?

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

Tomorrow if the implementation class of the IStudentRepository is changed then we also need to change the code in the HomeController class as they both are tightly coupled. We can overcome this problem by implementing the dependency injection design pattern in ASP.NET Core Application.

What is Dependency Injection (DI) Design Pattern?

The Dependency Injection a process of injecting the object of a class into a class that depends on it. The Dependency Injection is the most commonly used design pattern nowadays to remove the dependencies between the objects that allow us to develop loosely coupled software components.

Let us discuss the step by step procedure to implement dependency injection in ASP.NET Core MVC application.

Dependency Injection in ASP.NET Core:

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

.NET Core Dependency Injection

ASP.NET Core framework contains simple out-of-the-box IoC containers which do not have as many features as other third party IoC containers such as Unity, StructureMap, Castle Windsor, Ninject, etc. If you want more features such as auto-registration, scanning, interceptors, or decorators then you may replace the built-in IoC container with a third-party container.

The built-in container is represented by IServiceProvider implementation that supports constructor injection by default. The types (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) which you as a programmer create for your application.

In order to let the IoC container automatically inject our application services, we first need to register them with the IoC container.

How to register a Service with ASP.NET Core Dependency Injection Container?

We need to register a service with ASP.NET Core Dependency Injection Container within the ConfigureServices() method of the Startup class.

Before we discuss how to register a service with the Dependency Injection Container, it is important to understand the lifetime of service. When a class receives the dependency object through dependency injection, then whether the instance it receives is unique to that instance of the class or not depends on the lifetime of the service. Setting the lifetime of the dependency object determines how many times the dependency object needs to be created.

What are the different methods ASP.NET Core Provides to register a service with Dependency Injection Contains?

The ASP.NET core provides 3 methods to register a service with the ASP.NET Core Dependency Injection container as follows. The method that we use to register a service will determine the lifetime of that service.

  1. Singleton
  2. Transient
  3. Scoped

Singleton: In this case, the IoC container will create and share a single instance of a service object throughout the application’s lifetime.

Transient: In this case, the IoC container will create a new instance of the specified service type every time you ask for it.

Scoped: In this case, the IoC container will create an instance of the specified service type once per request and will be shared in a single request.

Note: The Built-in IoC container manages the lifetime of a registered service. It automatically disposes of a service instance based on the specified lifetime.

Registering the TestStudentRepository with ASP.NET Core Dependency Injection 

We need to configure the service instance within the ConfigureServices() method of the Startup class. The following code shows how to register a service with different lifetimes:

public void ConfigureServices(IServiceCollection services)
{
    //Adding MVC Service. Framework Service
    services.AddControllersWithViews();

    //Application Service
    services.Add(new ServiceDescriptor(typeof(IStudentRepository), new TestStudentRepository())); // by default singleton
    services.Add(new ServiceDescriptor(typeof(IStudentRepository), typeof(TestStudentRepository), ServiceLifetime.Singleton)); // singleton
    services.Add(new ServiceDescriptor(typeof(IStudentRepository), typeof(TestStudentRepository), ServiceLifetime.Transient)); // Transient
    services.Add(new ServiceDescriptor(typeof(IStudentRepository), typeof(TestStudentRepository), ServiceLifetime.Scoped));    // Scoped
}
Extension Methods for Registration

ASP.NET Core framework includes extension methods for each types of lifetime; AddSingleton(), AddTransient() and AddScoped() methods for singleton, transient and scoped lifetime respectively. The following example shows the ways of registering types (service) using extension methods.

public void ConfigureServices(IServiceCollection services)
{
    //Adding MVC Service. Framework Service
    services.AddControllersWithViews();

    //Application Service
    services.AddSingleton<IStudentRepository, TestStudentRepository>();
    services.AddSingleton(typeof(IStudentRepository), typeof(TestStudentRepository));

    services.AddTransient<IStudentRepository, TestStudentRepository>();
    services.AddTransient(typeof(IStudentRepository), typeof(TestStudentRepository));

    services.AddScoped<IStudentRepository, TestStudentRepository>();
    services.AddScoped(typeof(IStudentRepository), typeof(TestStudentRepository));
}

So, let us use the Single Instance of the service in this example. So, modify the ConfigureService method of the Startup class as shown below. Which method you want to use to register your application service to the built-in IoC Container is your personal preference. I am going to use the following.

public void ConfigureServices(IServiceCollection services)
{
    //Adding MVC Service. Framework Service
    services.AddControllersWithViews();

    //Application Service
    services.AddSingleton<IStudentRepository, TestStudentRepository>();
}

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 the Constructor dependency injection.

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 pass an instance of the TestStudentRepository to 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. As we are injecting the dependency object through a constructor, it is called as constructor dependency injection.

We created the _ repository variable as read-only which will ensure that once we injected the dependency object then 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.

ASP.NET Core Dependency Injection

Action Method Injection in ASP.NET Core Application

Sometimes we may only need a dependency service type in a single action method. For this, use the [FromServices] attribute with the service type parameter in the method.

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

namespace FirstCoreMVCWebApplication.Controllers
{
    public class HomeController : Controller
    {
        public HomeController()
        {
        }

        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.

Dependency Injection in .NET Core

Property Injection

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

Get Services Manually

It is not required to include dependency services in the constructor. We can access dependent services configured with built-in IoC containers manually using the RequestServices property of HttpContext as shown below.

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;
            var _repository = (IStudentRepository)services.GetService(typeof(IStudentRepository));
            List<Student> allStudentDetails = _repository.GetAllStudent();
            return Json(allStudentDetails);
        }

        public JsonResult GetStudentDetails(int Id)
        {
            var services = this.HttpContext.RequestServices;
            var _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 shown in the below image.

Dependency Injection in ASP.NET Core

Note: It is recommended to use constructor injection instead of getting it using RequestServices.

When to use what?

In real-time applications, you need to register the components such as application-wide configuration as Singleton. The Database access classes like Entity Framework contexts are recommended to be registered as Scoped so that the connection can be re-used. If you want to run anything in parallel then it is better to register the component as Transient.

So, in short:

AddSingleton(): When we use the AddSingleton() method to register a service, then it will create a singleton service. It means a single instance of that service is created and that singleton instance is shared among all the components of the application that require it. That singleton service is created when we requested for the first time.

AddScoped(): Scoped means instance per request. When we use the AddScoped() method to register a service, then it will create a Scoped service. It means, an instance of the service is created once per each HTTP request and uses that instance in other calls of the same request.

AddTransient(): When we use the AddTransient() method to register a service, then it will create a Transient service. It means a new instance of the specified service is created each time when it is requested and they are never shared.

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. Using the ASP.NET Core Dependency Injection, it is very easy to swap with a different implementation of a component.

In the next article, I am going to discuss the Controllers in ASP.NET Core MVC application. Here, in this article, I try to explain the ASP.NET Core Dependency Injection with an example. I hope this article will help you to understand the concept of Dependency Injection in ASP.NET Core Application. 

Reference:

Learn Design Patterns in Detail

Learn Dependency Injection in Detail

Learn IoC Containers in Detail

4 thoughts on “ASP.NET Core Dependency Injection”

Leave a Reply

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