Dependency Injection is the design pattern that help us to create application which loosely coupled. This means that object should only have those dependency that required during complete task. The main advantages of DI (Dependency Injection) is our application loosely coupled and has provide greater maintainability, testability and also re-usability.
There are three type of DI: Construction Injection, Setter Injection, Interface based Injection.
1. The Construction Injection type of DI accept their dependency at constructor level it means that when create object of the class, their dependency pass through the constructor of the class. It provide the strong dependency contract between objects.
2. The Setter Injection is also known as property injection. In this type of dependency injection, dependency pass through public property instead of constructor. It allows us to pass the dependencies when they required. It does not provide strong dependency contract between objects.
3. The interface-based dependency injection can be achieved by creating the common interface and other classes are implements this interface to inject the dependency. In this type of DI, we can use either constructor injection or setter injection.
There is a built-in support of dependency injection in ASP.net Core. This supports is not limited to middleware, but also support in Controllers, views, and model as well. There are two type of service container provided by the ASP.net core: Framework Services and Application Services. The framework services are service that are provided by the ASP.net core such as ILoggerFactory etc. The application services are the custom services created base on our requirement.
- Dependency injection into controllers -
ASP.NET Core supports Dependency Injection(DI) between classes and their dependencies. MVC Controllers request dependencies explicitly via constructors. Furthermore, ASP.NET Core has built-in support for dependency injection, hence making the application easier to test and maintain.
We add services as a constructor parameter and the runtime resolves the service from the service container. We typically define services using interfaces.
When we implement a repository pattern in the ASP.NET Core MVC application, we make use of Dependency Injection in our controllers.
Let’s create an ASP.NET Core MVC application and implement a simple data repository as described in the article.
First of all, let’s create an interface IDataRepository:
public interface IDataRepository<TEntity>
{
IEnumerable<TEntity> GetAll();
void Add(Employee employee);
}
Then let’s create a class EmployeeManager implementing the IDataRepository interface:
public class EmployeeManager : IDataRepository<Employee>
{
public void Add(Employee employee)
{
throw new NotImplementedException();
}
IEnumerable<Employee> IDataRepository<Employee>.GetAll()
{
return new List<Employee>()
{
new Employee(){ }
};
}
}
The next step is to add the service to the service container. We need to do that in the ConfigureServices() method in the Startup.cs class:
services.AddScoped<IDataRepository<Employee>, EmployeeManager>();
By doing so, we have configured the repository using Dependency Injection.
Next, let’s create the EmployeeController with the Index() action method to get the list of all employees:
public class EmployeeController : Controller
{
private readonly IDataRepository<Employee> _dataRepository;
public EmployeeController(IDataRepository<Employee> dataRepository)
{
_dataRepository = dataRepository;
}
public IActionResult Index()
{
IEnumerable<Employee> employees = _dataRepository.GetAll();
return View(employees);
}
}
Here, we first declare a _dataRepository variable of type IDataRepository<Employee>. Later, we inject it through the constructor.
We can also inject a service directly into an action method without using a constructor injection. We can use the [FromServices] attribute for that:
public IActionResult Index([FromServices] IDataRepository<Employee> _dataRepository)
{
IEnumerable<Employee> employees = _dataRepository.GetAll();
return View(employees);
}
TheFromServices attribute specifies that an action parameter should be bound using the request services.
Now, we have learned how to use Dependency Injection to provide dependencies into a Controller.
- Injecting Dependencies into Views -
We can inject a service into a view using the @inject directive. @inject adds a property to our view and initialize it using DI:
@inject <type> <name>
Let’s create a controller action method to display a book creation form:
public class BooksController : Controller
{
public IActionResult Create()
{
return View();
}
}
Then let’s create a Book model class:
public class Book
{
public int Id { get; set; }
[Display(Name = "Book Title")]
public string Title { get; set; }
public string Genre { get; set; }
[DataType(DataType.Currency)]
[Range(1, 100)]
public decimal Price { get; set; }
[Display(Name = "Publish Date")]
[DataType(DataType.Date)]
public DateTime PublishDate { get; set; }
}
For the next step, let’s define a BooksLookupService for supplying the list data for Genres:
public class BooksLookupService
{
public List<string> GetGenres()
{
return new List<string>()
{
"Fiction",
"Thriller",
"Comedy",
"Autobiography"
};
}
}
Then let’s create a view and inject an instance of BooksLookupService into it:
@model WorkingWithDI.Models.Book
@inject WorkingWithDI.Models.Services.BooksLookupService BooksLookupService
@{
ViewData["Title"] = "Create";
var genres = BooksLookupService.GetGenres();
}
<h1>Create</h1>
<h4>Book</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div>
<label asp-for="Genre" class="control-label"></label>
<select asp-items="@(new SelectList(genres))" class="form-control" ></select>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PublishDate" class="control-label"></label>
<input asp-for="PublishDate" class="form-control" />
<span asp-validation-for="PublishDate" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
This will supply the list values into the view.
As the last step, we need to register the types that we request through dependency injection in Startup.ConfigureServices(). If a type is unregistered, it throws a runtime exception.
services.AddTransient<BooksLookupService>();
That’s it. Now let’s run the application and navigate to Create Books form:
We can see that the list of Genres is populated by getting the values from the BooksLookupService.
Now, we have learned how to inject a dependency directly into the view.