Introduction
Dependency injection is a software design pattern that enables users to create an application with loosely coupled code. The term 'loosely coupled' means objects that should only have as many dependencies as required to complete their job by decreasing the tight coupling between the software components. Object's dependencies should be on interfaces as opposed to the concrete object. An object is concrete in the sense that it is created with the "new" keyword.
Advantages of Dependency Injection
- Easier Maintainability
- Greater re-usability
Code is more easily testable with different mock implementation.
Code is cleaner and more readable
There are basically 3 types of Dependency injection in ASP.NET Core:
- Constructor Injection
- Method Injection
- Property Injection
Constructor Injection
Constructor injection is the most common dependency injection used in an application. Constructor injection uses parameters to inject the dependency. It accepts the dependency at the constructor level. It means when instantiating the class, their dependency pass through the constructor of the class.
Implementing Constructor Injection
In the below code, HomeController has a dependency on IEmployeeRepository. We are not creating an object of EmployeeRepository using the new Keyword but we are injecting IEmployeeRepository in Home Controller class using its constructor. This is called constructor injection.
- using DependencyInjectionTech.Models;
- using Microsoft.AspNetCore.Mvc;
- namespace DependencyInjectionTech.Controllers {
- [Route("api/[controller]")]
- [ApiController]
- public class HomeController: ControllerBase {
- private IEmployeeRepository _employeeRepository;
-
- public HomeController(IEmployeeRepository employeeRepository) {
- _employeeRepository = employeeRepository;
- }
- [HttpGet]
- [Produces("application/json")]
- public Employee GetEmployee() {
- return _employeeRepository.GetEmployee(1);
- }
- }
- }
While running the application, we will get the below error because we have to manually register the interface IEmployeeRepository and its implementation class in the Asp.Net Core dependency injection container. Unless we won't do that process, we will get the below error:
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type 'DependencyInjectionTech.Models.IEmployeeRepository' while attempting to activate 'DependencyInjectionTech.Controllers.HomeController'.
For registering the interface and its implementation, we have a startup class where we configure the service methods. We make use of the ConfigureServices method to configure the required service for our application. We can use this method to configure in both the ASP.NET Framework Service as well as our application-related custom service. We can make use of the incoming parameter type IServiceCollection of the Configure service method to configure the service.
There are basically 3 methods to register our custom service in the configure service method:
- Add Singleton
- Add Transient
- Add Scoped
The below code in the startup file indicates if any controller (for example HomeController) requests IEmployeeRepository. Then it will automatically create an instance of MockEmployeeRepository class and then inject the instance.
-
- public void ConfigureServices(IServiceCollection services) {
- services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
-
- services.AddSingleton < IEmployeeRepository, MockEmployeeRepository > ();
- }
Method Injection
Method Injection enables you to inject the dependency into a single method to be only used by that method. We make use of the [FromService] attribute for the method Injection.
Implementing the Method Injection
In the below code, we are implementing the method injection in a single method.
- namespace DependencyInjectionTech.Controllers {
- [Route("api/[controller]")]
- [ApiController]
- public class HomeController: ControllerBase {
- public HomeController() {}
-
- [HttpGet]
- [Produces("application/json")]
- public Employee GetEmployee([FromServices] IEmployeeRepository _employeeRepository) {
- return _employeeRepository.GetEmployee(1);
- }
- }
- }