Dependency injection into views in ASP.NET Core (2024)

  • Article

ASP.NET Core supports dependency injection into views. This can be useful for view-specific services, such as localization or data required only for populating view elements. Most of the data views display should be passed in from the controller.

View or download sample code (how to download)

Configuration injection

The values in settings files, such as appsettings.json and appsettings.Development.json, can be injected into a view. Consider the appsettings.Development.json from the sample code:

{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "MyRoot": { "MyParent": { "MyChildName": "Joe" } }}

The following markup displays the configuration value in a Razor Pages view:

@page@model PrivacyModel@using Microsoft.Extensions.Configuration@inject IConfiguration Configuration@{ ViewData["Title"] = "Privacy RP";}<h1>@ViewData["Title"]</h1><p>PR Privacy</p><h2> MyRoot:MyParent:MyChildName: @Configuration["MyRoot:MyParent:MyChildName"]</h2>

The following markup displays the configuration value in a MVC view:

@using Microsoft.Extensions.Configuration@inject IConfiguration Configuration@{ ViewData["Title"] = "Privacy MVC";}<h1>@ViewData["Title"]</h1><p>MVC Use this page to detail your site's privacy policy.</p><h2> MyRoot:MyParent:MyChildName: @Configuration["MyRoot:MyParent:MyChildName"]</h2>

For more information, see Configuration in ASP.NET Core

Service injection

A service can be injected into a view using the @inject directive.

@using System.Threading.Tasks@using ViewInjectSample.Model@using ViewInjectSample.Model.Services@model IEnumerable<ToDoItem>@inject StatisticsService StatsService<!DOCTYPE html><html><head> <title>To Do Items</title></head><body> <div> <h1>To Do Items</h1> <ul> <li>Total Items: @StatsService.GetCount()</li> <li>Completed: @StatsService.GetCompletedCount()</li> <li>Avg. Priority: @StatsService.GetAveragePriority()</li> </ul> <table> <tr> <th>Name</th> <th>Priority</th> <th>Is Done?</th> </tr> @foreach (var item in Model) { <tr> <td>@item.Name</td> <td>@item.Priority</td> <td>@item.IsDone</td> </tr> } </table> </div></body></html>

This view displays a list of ToDoItem instances, along with a summary showing overall statistics. The summary is populated from the injected StatisticsService. This service is registered for dependency injection in ConfigureServices in Program.cs:

using ViewInjectSample.Helpers;using ViewInjectSample.Infrastructure;using ViewInjectSample.Interfaces;using ViewInjectSample.Model.Services;var builder = WebApplication.CreateBuilder(args);builder.Services.AddControllersWithViews();builder.Services.AddRazorPages();builder.Services.AddTransient<IToDoItemRepository, ToDoItemRepository>();builder.Services.AddTransient<StatisticsService>();builder.Services.AddTransient<ProfileOptionsService>();builder.Services.AddTransient<MyHtmlHelper>();var app = builder.Build();if (!app.Environment.IsDevelopment()){ app.UseExceptionHandler("/Home/Error"); app.UseHsts();}app.UseHttpsRedirection();app.UseStaticFiles();app.UseRouting();app.MapRazorPages();app.MapDefaultControllerRoute();app.Run();

The StatisticsService performs some calculations on the set of ToDoItem instances, which it accesses via a repository:

using System.Linq;using ViewInjectSample.Interfaces;namespace ViewInjectSample.Model.Services{ public class StatisticsService { private readonly IToDoItemRepository _toDoItemRepository; public StatisticsService(IToDoItemRepository toDoItemRepository) { _toDoItemRepository = toDoItemRepository; } public int GetCount() { return _toDoItemRepository.List().Count(); } public int GetCompletedCount() { return _toDoItemRepository.List().Count(x => x.IsDone); } public double GetAveragePriority() { if (_toDoItemRepository.List().Count() == 0) { return 0.0; } return _toDoItemRepository.List().Average(x => x.Priority); } }}

The sample repository uses an in-memory collection. An in-memory implementation shouldn't be used for large, remotely accessed data sets.

The sample displays data from the model bound to the view and the service injected into the view:

Dependency injection into views in ASP.NET Core (1)

Populating Lookup Data

View injection can be useful to populate options in UI elements, such as dropdown lists. Consider a user profile form that includes options for specifying gender, state, and other preferences. Rendering such a form using a standard approach might require the controller or Razor Page to:

  • Request data access services for each of the sets of options.
  • Populate a model or ViewBag with each set of options to be bound.

An alternative approach injects services directly into the view to obtain the options. This minimizes the amount of code required by the controller or razor Page, moving this view element construction logic into the view itself. The controller action or Razor Page to display a profile editing form only needs to pass the form the profile instance:

using Microsoft.AspNetCore.Mvc;using ViewInjectSample.Model;namespace ViewInjectSample.Controllers;public class ProfileController : Controller{ public IActionResult Index() { // A real app would up profile based on the user. var profile = new Profile() { Name = "Rick", FavColor = "Blue", Gender = "Male", State = new State("Ohio","OH") }; return View(profile); }}

The HTML form used to update the preferences includes dropdown lists for three of the properties:

Dependency injection into views in ASP.NET Core (2)

These lists are populated by a service that has been injected into the view:

@using System.Threading.Tasks@using ViewInjectSample.Model.Services@model ViewInjectSample.Model.Profile@inject ProfileOptionsService Options<!DOCTYPE html><html><head> <title>Update Profile</title></head><body><div> <h1>Update Profile</h1> Name: @Html.TextBoxFor(m => m.Name) <br/> Gender: @Html.DropDownList("Gender", Options.ListGenders().Select(g => new SelectListItem() { Text = g, Value = g })) <br/> State: @Html.DropDownListFor(m => m.State!.Code, Options.ListStates().Select(s => new SelectListItem() { Text = s.Name, Value = s.Code})) <br /> Fav. Color: @Html.DropDownList("FavColor", Options.ListColors().Select(c => new SelectListItem() { Text = c, Value = c })) </div></body></html>

The ProfileOptionsService is a UI-level service designed to provide just the data needed for this form:

namespace ViewInjectSample.Model.Services;public class ProfileOptionsService{ public List<string> ListGenders() { // Basic sample return new List<string>() {"Female", "Male"}; } public List<State> ListStates() { // Add a few states return new List<State>() { new State("Alabama", "AL"), new State("Alaska", "AK"), new State("Ohio", "OH") }; } public List<string> ListColors() { return new List<string>() { "Blue","Green","Red","Yellow" }; }}

Note an unregistered type throws an exception at runtime because the service provider is internally queried via GetRequiredService.

Overriding Services

In addition to injecting new services, this technique can be used to override previously injected services on a page. The figure below shows all of the fields available on the page used in the first example:

Dependency injection into views in ASP.NET Core (3)

The default fields include Html, Component, and Url. To replace the default HTML Helpers with a custom version, use @inject:

@using System.Threading.Tasks@using ViewInjectSample.Helpers@inject MyHtmlHelper Html<!DOCTYPE html><html><head> <title>My Helper</title></head><body> <div> Test: @Html.Value </div></body></html>

See Also

ASP.NET Core supports dependency injection into views. This can be useful for view-specific services, such as localization or data required only for populating view elements. You should try to maintain separation of concerns between your controllers and views. Most of the data your views display should be passed in from the controller.

View or download sample code (how to download)

Configuration injection

appsettings.json values can be injected directly into a view.

Example of an appsettings.json file:

{ "root": { "parent": { "child": "myvalue" } }}

The syntax for @inject:@inject <type> <name>

An example using @inject:

@using Microsoft.Extensions.Configuration@inject IConfiguration Configuration@{ string myValue = Configuration["root:parent:child"]; ...}

Service injection

A service can be injected into a view using the @inject directive. You can think of @inject as adding a property to the view, and populating the property using DI.

@using System.Threading.Tasks@using ViewInjectSample.Model@using ViewInjectSample.Model.Services@model IEnumerable<ToDoItem>@inject StatisticsService StatsService<!DOCTYPE html><html><head> <title>To Do Items</title></head><body> <div> <h1>To Do Items</h1> <ul> <li>Total Items: @StatsService.GetCount()</li> <li>Completed: @StatsService.GetCompletedCount()</li> <li>Avg. Priority: @StatsService.GetAveragePriority()</li> </ul> <table> <tr> <th>Name</th> <th>Priority</th> <th>Is Done?</th> </tr> @foreach (var item in Model) { <tr> <td>@item.Name</td> <td>@item.Priority</td> <td>@item.IsDone</td> </tr> } </table> </div></body></html>

This view displays a list of ToDoItem instances, along with a summary showing overall statistics. The summary is populated from the injected StatisticsService. This service is registered for dependency injection in ConfigureServices in Startup.cs:

public class Startup{ // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc();

The StatisticsService performs some calculations on the set of ToDoItem instances, which it accesses via a repository:

using System.Linq;using ViewInjectSample.Interfaces;namespace ViewInjectSample.Model.Services{ public class StatisticsService { private readonly IToDoItemRepository _toDoItemRepository; public StatisticsService(IToDoItemRepository toDoItemRepository) { _toDoItemRepository = toDoItemRepository; } public int GetCount() { return _toDoItemRepository.List().Count(); } public int GetCompletedCount() { return _toDoItemRepository.List().Count(x => x.IsDone); } public double GetAveragePriority() { if (_toDoItemRepository.List().Count() == 0) { return 0.0; } return _toDoItemRepository.List().Average(x => x.Priority); } }}

The sample repository uses an in-memory collection. The implementation shown above (which operates on all of the data in memory) isn't recommended for large, remotely accessed data sets.

The sample displays data from the model bound to the view and the service injected into the view:

Dependency injection into views in ASP.NET Core (4)

Populating Lookup Data

View injection can be useful to populate options in UI elements, such as dropdown lists. Consider a user profile form that includes options for specifying gender, state, and other preferences. Rendering such a form using a standard MVC approach would require the controller to request data access services for each of these sets of options, and then populate a model or ViewBag with each set of options to be bound.

An alternative approach injects services directly into the view to obtain the options. This minimizes the amount of code required by the controller, moving this view element construction logic into the view itself. The controller action to display a profile editing form only needs to pass the form the profile instance:

using Microsoft.AspNetCore.Mvc;using ViewInjectSample.Model;namespace ViewInjectSample.Controllers{ public class ProfileController : Controller { [Route("Profile")] public IActionResult Index() { // TODO: look up profile based on logged-in user var profile = new Profile() { Name = "Steve", FavColor = "Blue", Gender = "Male", State = new State("Ohio","OH") }; return View(profile); } }}

The HTML form used to update these preferences includes dropdown lists for three of the properties:

Dependency injection into views in ASP.NET Core (5)

These lists are populated by a service that has been injected into the view:

@using System.Threading.Tasks@using ViewInjectSample.Model.Services@model ViewInjectSample.Model.Profile@inject ProfileOptionsService Options<!DOCTYPE html><html><head> <title>Update Profile</title></head><body><div> <h1>Update Profile</h1> Name: @Html.TextBoxFor(m => m.Name) <br/> Gender: @Html.DropDownList("Gender", Options.ListGenders().Select(g => new SelectListItem() { Text = g, Value = g })) <br/> State: @Html.DropDownListFor(m => m.State.Code, Options.ListStates().Select(s => new SelectListItem() { Text = s.Name, Value = s.Code})) <br /> Fav. Color: @Html.DropDownList("FavColor", Options.ListColors().Select(c => new SelectListItem() { Text = c, Value = c })) </div></body></html>

The ProfileOptionsService is a UI-level service designed to provide just the data needed for this form:

using System.Collections.Generic;namespace ViewInjectSample.Model.Services{ public class ProfileOptionsService { public List<string> ListGenders() { // keeping this simple return new List<string>() {"Female", "Male"}; } public List<State> ListStates() { // a few states from USA return new List<State>() { new State("Alabama", "AL"), new State("Alaska", "AK"), new State("Ohio", "OH") }; } public List<string> ListColors() { return new List<string>() { "Blue","Green","Red","Yellow" }; } }}

Important

Don't forget to register types you request through dependency injection in Startup.ConfigureServices. An unregistered type throws an exception at runtime because the service provider is internally queried via GetRequiredService.

Overriding Services

In addition to injecting new services, this technique can also be used to override previously injected services on a page. The figure below shows all of the fields available on the page used in the first example:

Dependency injection into views in ASP.NET Core (6)

As you can see, the default fields include Html, Component, and Url (as well as the StatsService that we injected). If for instance you wanted to replace the default HTML Helpers with your own, you could easily do so using @inject:

@using System.Threading.Tasks@using ViewInjectSample.Helpers@inject MyHtmlHelper Html<!DOCTYPE html><html><head> <title>My Helper</title></head><body> <div> Test: @Html.Value </div></body></html>

If you want to extend existing services, you can simply use this technique while inheriting from or wrapping the existing implementation with your own.

See Also

As a seasoned expert in ASP.NET Core development, I bring a wealth of experience and knowledge to the table. I've been deeply involved in the architecture, design, and implementation of various ASP.NET Core applications, and my expertise extends to key concepts such as dependency injection, configuration management, and service injection.

The article you provided delves into advanced topics related to ASP.NET Core, specifically focusing on dependency injection into views. Let's break down the key concepts discussed in the article:

1. Configuration Injection:

  • Purpose: To inject values from configuration files (e.g., appsettings.json) directly into views.
  • Example: The article demonstrates injecting a configuration value into a Razor Pages view and an MVC view using the @inject IConfiguration directive.

2. Service Injection:

  • Purpose: To inject services directly into views, allowing access to specific functionalities or data within the view.

  • Example: The article showcases injecting a StatisticsService into a view to display statistics related to ToDoItem instances. The service is registered in the ConfigureServices method of the Startup.cs file.

  • Service Implementation:

    • The StatisticsService performs calculations on a set of ToDoItem instances using an injected IToDoItemRepository.
    • The repository is registered as a transient service in the ConfigureServices method.

3. Populating Lookup Data via Service Injection:

  • Purpose: To populate options in UI elements (e.g., dropdown lists) by injecting a service directly into the view.
  • Example: The article demonstrates injecting a ProfileOptionsService into a view to populate dropdown lists in a user profile form.

4. Overriding Services:

  • Purpose: To override previously injected services on a page, allowing customization or extension of default behaviors.
  • Example: The article illustrates overriding default HTML Helpers with a custom version using the @inject directive.

5. Best Practices and Considerations:

  • The article emphasizes maintaining a separation of concerns between controllers and views, advocating for passing most of the data from controllers to views.

6. Important Notes:

  • Types requested through dependency injection must be registered in the ConfigureServices method in the Startup.cs file.

In conclusion, the article provides comprehensive insights into leveraging dependency injection, configuration management, and service injection to enhance the functionality and maintainability of ASP.NET Core applications. The examples and explanations offer a deep understanding of these advanced concepts in the context of real-world scenarios.

Dependency injection into views in ASP.NET Core (2024)

References

Top Articles
Latest Posts
Article information

Author: Lilliana Bartoletti

Last Updated:

Views: 6236

Rating: 4.2 / 5 (73 voted)

Reviews: 80% of readers found this page helpful

Author information

Name: Lilliana Bartoletti

Birthday: 1999-11-18

Address: 58866 Tricia Spurs, North Melvinberg, HI 91346-3774

Phone: +50616620367928

Job: Real-Estate Liaison

Hobby: Graffiti, Astronomy, Handball, Magic, Origami, Fashion, Foreign language learning

Introduction: My name is Lilliana Bartoletti, I am a adventurous, pleasant, shiny, beautiful, handsome, zealous, tasty person who loves writing and wants to share my knowledge and understanding with you.