Injection de dépendances dans les vues dans ASP.NET CoreDependency injection into views in ASP.NET Core

Par Steve SmithBy Steve Smith

ASP.NET Core prend en charge l’injection de dépendances dans les vues.ASP.NET Core supports dependency injection into views. Cette fonctionnalité peut être utile pour les services spécifiques à une vue, notamment la localisation ou les données requises uniquement pour remplir les éléments de la vue.This can be useful for view-specific services, such as localization or data required only for populating view elements. Vous devez essayer de respecter le principe de séparation des préoccupations entre les contrôleurs et les vues.You should try to maintain separation of concerns between your controllers and views. La plupart des données affichées dans vos vues doivent être passées par le contrôleur.Most of the data your views display should be passed in from the controller.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)View or download sample code (how to download)

Injection de configurationConfiguration injection

Les valeurs appsettings.json peuvent être injectées directement dans une vue.appsettings.json values can be injected directly into a view.

Exemple de fichier appsettings.json :Example of an appsettings.json file:

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

Syntaxe de la directive @inject : @inject <type> <name>The syntax for @inject: @inject <type> <name>

Exemple avec @inject :An example using @inject:

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

Injection de serviceService injection

Un service peut être injecté dans une vue en utilisant la directive @inject.A service can be injected into a view using the @inject directive. @inject équivaut à ajouter une propriété à la vue et à remplir la propriété à l’aide de l’injection de dépendances.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>

Cette vue affiche une liste d’instances ToDoItem et un récapitulatif de statistiques générales.This view displays a list of ToDoItem instances, along with a summary showing overall statistics. Le récapitulatif est rempli avec les données du service StatisticsService injecté.The summary is populated from the injected StatisticsService. Ce service est inscrit pour l’injection de dépendances sous ConfigureServices dans Startup.cs :This service is registered for dependency injection in ConfigureServices in Startup.cs:

// 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 effectue des calculs sur l’ensemble des instances ToDoItem, auquel il accède par le biais d’un référentiel :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);
        }
    }
}

Le référentiel de l’exemple utilise une collection en mémoire.The sample repository uses an in-memory collection. L’implémentation illustrée ci-dessus (qui s’applique à toutes les données en mémoire) n’est pas recommandée pour les jeux de données volumineux et accessibles à distance.The implementation shown above (which operates on all of the data in memory) isn't recommended for large, remotely accessed data sets.

L’exemple affiche les données fournies par le modèle lié à la vue et le service injecté dans la vue :The sample displays data from the model bound to the view and the service injected into the view:

La vue des tâches To Do affiche le nombre total de tâches et de tâches terminées, la priorité moyenne, et une liste des tâches avec leur niveau de priorité et une valeur booléenne indiquant leur statut.

Remplissage des données de recherchePopulating Lookup Data

L’injection dans les vues peut être utile pour remplir certaines options dans les éléments d’interface utilisateur, telles que les listes déroulantes.View injection can be useful to populate options in UI elements, such as dropdown lists. Prenons l’exemple d’un formulaire de profil utilisateur qui comporte des options permettant de spécifier le sexe, l’État et d’autres préférences.Consider a user profile form that includes options for specifying gender, state, and other preferences. Pour afficher un formulaire de ce type selon une approche MVC standard, il faudrait que le contrôleur demande l’accès des données aux services pour chacune des options du formulaire, puis qu’il remplisse un modèle ou ViewBag avec chaque ensemble d’options à lier.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.

Une autre approche consiste à injecter les services directement dans la vue pour obtenir les options.An alternative approach injects services directly into the view to obtain the options. Cela réduit la quantité de code requis par le contrôleur, car la logique de construction de cet élément de vue est déplacée dans la vue proprement dite.This minimizes the amount of code required by the controller, moving this view element construction logic into the view itself. Pour afficher un formulaire de modification de profil, il suffit ainsi au contrôleur de passer l’instance de profil au formulaire :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);
        }
    }
}

Le formulaire HTML utilisé pour mettre à jour ces préférences inclut des listes déroulantes pour trois des propriétés :The HTML form used to update these preferences includes dropdown lists for three of the properties:

Vue de mise à jour du profil, avec un formulaire de saisie d’informations (nom, sexe, État et couleur préférée).

Ces listes sont remplies par un service qui a été injecté dans la vue :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>

ProfileOptionsService est un service au niveau de l’interface utilisateur qui est conçu pour fournir uniquement les données nécessaires dans ce formulaire :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

N’oubliez pas d’inscrire les types à demander par le biais de l’injection de dépendances dans Startup.ConfigureServices.Don't forget to register types you request through dependency injection in Startup.ConfigureServices. Un type non inscrit lève une exception au moment de l’exécution, car le fournisseur de services est interrogé en interne par le biais de GetRequiredService.An unregistered type throws an exception at runtime because the service provider is internally queried via GetRequiredService.

Substitution de servicesOverriding Services

L’injection de services peut être utilisée pour injecter de nouveaux services, mais également pour substituer des services ayant déjà été injectés dans une page.In addition to injecting new services, this technique can also be used to override previously injected services on a page. La capture d’écran ci-dessous montre tous les champs disponibles dans la page utilisée dans le premier exemple :The figure below shows all of the fields available on the page used in the first example:

Menu contextuel IntelliSense pour un symbole @ entré qui affiche les champs Html, Component, StatsService et Url

Comme vous pouvez le voir, les champs par défaut incluent Html, Component et Url (mais aussi StatsService que nous avons injecté).As you can see, the default fields include Html, Component, and Url (as well as the StatsService that we injected). Si vous souhaitez, par exemple, remplacer les HTML Helpers par défaut par les vôtres, vous pouvez facilement le faire en utilisant @inject :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>

Si vous souhaitez étendre des services existants, vous pouvez simplement utiliser cette technique en héritant de ou en incluant dans un wrapper l’implémentation existante avec la vôtre.If you want to extend existing services, you can simply use this technique while inheriting from or wrapping the existing implementation with your own.

Voir aussiSee Also