ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. For more information specific to dependency injection within MVC controllers, see Dependency injection into controllers in ASP.NET Core.
What is ASP.NET Core Dependency Injection?. The Complete ASP.NET Core Developer Course 2022 [Videos].
ASP.NET Core Dependency Injection with Example
In this Video, I am going to discuss the ASP.NET Core Dependency Injection with an example. Please watch our previous Video before proceeding to this Video 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 Video, we are going to discuss the following pointers in details.
- Understanding the need for ASP.NET Core Dependency Injection
- What is Dependency Injection?
- How to register a Service with ASP.NET Core Dependency Injection Container?
- What are the different methods ASP.NET Core Provides to register a service with Dependency Injection Contains?
- Understanding the Singleton, Scoped, and Transient Methods
- 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.
Once you created the Project with the Empty Project template, then lets 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.
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.
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.
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.
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.
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.
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:
- Framework Services: Services that are a part of the ASP.NET Core framework such as IApplicationBuilder, IHostingEnvironment, ILoggerFactory, etc.
- 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.
Singleton: In this case, the IoC container will create and share a single instance of a service object throughout the applications 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:
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.
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.
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.
In the above example, the IoC container will automatically pass an instance of the TestStudentRepository to the constructor of HomeController. We dont 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 watch-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.
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.
Run the application and you will get the expected output as shown below.
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.
With the above changes in place, run the application and you should get the output as expected as shown in the below image.
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.