Injecting dependencies into views in ASP.NET Core

ASP.NET Core support Dependency injection To view. This is useful for view specific services, such as localization or data needed only to populate view elements. Try to keep the distance between the controller and the view Problem separation . Most of the data displayed by the view should be passed in from the controller.

Configuration injection

appsettings.json   You can inject values directly into the view.

appsettings.json   File example:

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

@inject   Syntax: @ inject < type > < name >

use  @ inject   Examples of:

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

Service injection

have access to  @ inject   Directive injects services into the view. Can  @ inject   Treat as adding attributes to the view, and then populate the attributes with 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 shows   ToDoItem   A list of instances and a summary showing overall statistics. Summary from injected   StatisticsService   Fill in. In Startup.cs   ConfigureServices   Register this service for dependency injection in:

// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddTransient<IToDoItemRepository, ToDoItemRepository>();
    services.AddTransient<StatisticsService>();
    services.AddTransient<ProfileOptionsService>();

StatisticsService   Access through repository   ToDoItem   Instance set and perform some calculations:

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);
        }
    }
}

Fill lookup data

View injection can be used to populate options in UI elements, such as drop-down lists. Consider a user profile form that contains options for specifying gender, status, and other preferences. To render such a form using the standard MVC method, you need to ask the controller to request data access services for each group of options, and then populate the model or database with each group of options to be bound   ViewBag.

Another approach is to inject services directly into the view to get options. This minimizes the amount of code required by the controller and moves the view element construction logic into the view itself. The controller operation that displays the profile editing form only needs to pass the form of 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 a drop-down list of three properties:

 

 

These lists are populated by services that have 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>

ProfileOptionsService   Is a UI level service designed to accurately provide the data required by 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

Please remember in Startup.ConfigureServices Register the type of dependency injection request in. The type of unregister will throw an exception at run time because the service provider passed GetRequiredService Accept internal queries.

Alternative services

In addition to injecting new services, this method can also be used to replace the services previously injected on the page. The following figure shows all the available fields on the page used in the first example:

 

  As you can see, include default fields   Html,Component   and   Url (and what we injected)   StatsService). If you want to replace the default HTML helper with your own HTML helper, use  @ inject   Easy:

@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>

Official documents from Microsoft: https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/dependency-injection?view=aspnetcore-6.0

Posted on Fri, 03 Dec 2021 02:46:54 -0500 by maff20