In this article, we are going to discuss an important concept of ASP.NET Core MVC – Dependency Injection.
If you’ve missed some of the previous articles in the series we recommend visiting the series page: ASP.NET Core MVC Series.
To download this article’s source code visit: Dependency Injection in ASP.NET Core MVC.
So, let’s get down to it.
Dependency Inversion and Dependency Injection
Dependency Inversion
is one of the core software design principles which we use to create modules that are loosely coupled. While creating applications, we can achieve this using a technique called Dependency Injection
. Dependency Injection (DI)
is the method of injecting the dependent modules into our classes.
We have discussed this in detail in one of our other article Dependency Inversion Principle. We’ve also discussed the concept of Dependency Injection and how to implement it.
So, in this section, we are going to look at the support for Dependency Injection in an ASP.NET Core MVC application.
Injecting Dependencies 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. We have explained how to implement a simple data repository in the article section Implementing a simple data repository.
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.
Great. We have learned how to use Dependency Injection to provide dependencies into a Controller.
Now, let’s look at how to Inject dependencies into Views.
Injecting Dependencies into Views
ASP.NET Core supports injecting dependencies into Views.
When to Inject Dependencies into Views
Injecting services into views is a deviation from the MVC concept. But in some cases, we may have view-specific services which return the data that we use only for populating the view elements. An example is a service that gives a set of values that we need to display in a list control. In such scenarios, we can inject services directly into views. View injection can be useful to populate options in UI elements, such as dropdown lists.
Consider a form to create a book that includes options for specifying a genre. Rendering the data using a standard MVC approach would require the controller to request data access services for this set of options and then populate a Model or ViewBag with the set of options to be bound.
An alternative approach is to inject the services directly into a view. This approach minimizes the amount of code required by the controller as we move the view element construction logic into the view itself.
How to Inject services 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
.
Excellent, we have learned how to inject a dependency directly into the view.
Conclusion
In this article we have learned the following topics:
- The principle of Dependency Inversion and how to achieve it using Dependency Injection
- Injecting dependencies into Controllers
- Injecting dependencies into Views of an ASP.NET Core MVC application
In the next part of this series, we are going to learn about unit testing in ASP.NET Core MVC.