Dependency Injection in Ansichten in ASP.NET CoreDependency injection into views in ASP.NET Core

Von Steve SmithBy Steve Smith

ASP.NET Core unterstützt Dependency Injection in Ansichten.ASP.NET Core supports dependency injection into views. Dies kann besonders für ansichtsspezifische Dienste nützlich sein – z.B. für die Lokalisierung oder für Daten, die nur zum Auffüllen von Ansichtselementen erforderlich sind.This can be useful for view-specific services, such as localization or data required only for populating view elements. Sie sollten versuchen, das Prinzip Separation of Concerns zwischen Controllern und Ansichten beizubehalten.You should try to maintain separation of concerns between your controllers and views. Die meisten Daten, die in Ihren Ansichten angezeigt werden, sollten vom Controller übergeben worden sein.Most of the data your views display should be passed in from the controller.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)View or download sample code (how to download)

KonfigurationsinjektionConfiguration injection

appsettings.jason-Werte können direkt in eine Ansicht eingefügt werden.appsettings.json values can be injected directly into a view.

Beispiel einer appsettings.json-Datei:Example of an appsettings.json file:

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

Die Syntax für @inject: @inject <type> <name>The syntax for @inject: @inject <type> <name>

Ein Beispiel, das @inject verwendet:An example using @inject:

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

DienstinjektionService injection

Ein Dienst kann mithilfe der @inject-Anweisung in eine Ansicht eingefügt werden.A service can be injected into a view using the @inject directive. @inject fügt der Ansicht eine Eigenschaft hinzu und füllt diese Eigenschaft mittels Dependency Injection auf.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>

In dieser Ansicht wird neben einer Zusammenfassung von allgemeinen Statistiken eine Liste von ToDoItem-Instanzen angezeigt.This view displays a list of ToDoItem instances, along with a summary showing overall statistics. Die Zusammenfassung wird über den eingefügten StatisticsService-Dienst aufgefüllt.The summary is populated from the injected StatisticsService. Dieser Dienst ist für Dependency Injection in ConfigureServices in Startup.cs registriert: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>();

Die StatisticsService führt Berechnungen für die ToDoItem-Instanzen durch, auf die er über ein Repository zugreift: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);
        }
    }
}

Das Beispielrepository verwendet eine speicherinterne Auflistung.The sample repository uses an in-memory collection. Die obenstehend dargestellte Implementierung (die auf allen Daten im Arbeitsspeicher ausgeführt wird) wird nicht für große Datasets empfohlen, auf die über eine Remoteverbindung zugegriffen wird.The implementation shown above (which operates on all of the data in memory) isn't recommended for large, remotely accessed data sets.

Das Beispiel stellt Daten aus dem Modell, die an die Ansicht gebunden sind, und den in die Ansicht eingefügten Dienst dar:The sample displays data from the model bound to the view and the service injected into the view:

Die „Zu erledigen“-Ansicht, die die Gesamtelemente, fertiggestellte Elemente, durchschnittliche Priorität und eine Liste mit Aufgaben enthält, deren Prioritätsstufen und boolesche Werte auf die Fertigstellung hindeuten.

Auffüllen von NachschlagedatenPopulating Lookup Data

Die Ansichtsinjektion kann nützlich sein, wenn Sie Optionen in Benutzeroberflächenelemente wie Dropdownlisten einfügen möchten.View injection can be useful to populate options in UI elements, such as dropdown lists. Verwenden Sie ggf. ein Benutzerprofilformular, das Optionen zum Festlegen des Geschlechts, des Staats und anderer Vorlieben beinhaltet.Consider a user profile form that includes options for specifying gender, state, and other preferences. Wenn Sie ein solches Formular über einen Standard-MVC-Ansatz rendern, muss der Controller Datenzugriffsdienste für all diese Optionen anfordern, und dann ein Modell oder ViewBag mit den Optionen auffüllen, die gebunden werden sollen.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.

Über einen alternativen Ansatz werden Dienste direkt in die Ansicht eingefügt, um die Optionen abzurufen.An alternative approach injects services directly into the view to obtain the options. Dadurch ist weniger Code für den Controller erforderlich, denn die Konstruktionsebene dieses Ansichtselements wird in die Ansicht verschoben.This minimizes the amount of code required by the controller, moving this view element construction logic into the view itself. Die Controlleraktion, die das Formular zur Profilbearbeitung anzeigen soll, muss das Formular nur an die Profilinstanz übergeben: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);
        }
    }
}

Das HTML-Formular, das verwendet wird, um diese Vorlieben zu aktualisieren, umfasst Dropdownlisten für drei Eigenschaften:The HTML form used to update these preferences includes dropdown lists for three of the properties:

Die „Profil aktualisieren“-Ansicht mit einem Formular, in das der Name, das Geschlecht, der Staat und die Lieblingsfarbe eingetragen werden kann.

Die Listen werden über einen Dienst aufgefüllt, der in die Ansicht eingefügt wurde: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 ist ein Dienst auf Benutzeroberflächenebene, der nur die für das Formular benötigten Daten einfügt: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" };
        }
    }
}

Wichtig

Denken Sie daran, Typen zu registrieren, die Sie über Dependency Injection in Startup.ConfigureServices anfordern.Don't forget to register types you request through dependency injection in Startup.ConfigureServices. Ein nicht registrierter Typ löst eine Ausnahme zur Laufzeit aus, weil der Dienstanbieter intern über GetRequiredService abgefragt wird.An unregistered type throws an exception at runtime because the service provider is internally queried via GetRequiredService.

Überschreiben von DienstenOverriding Services

Sie können über diese Technik nicht nur neue Dienste einfügen, sondern auch zuvor auf einer Seite eingefügte Dienste überschreiben.In addition to injecting new services, this technique can also be used to override previously injected services on a page. In der nachfolgenden Abbildung werden alle Felder angezeigt, die auf der Seite verfügbar sind, die im ersten Beispiel verwendet wird:The figure below shows all of the fields available on the page used in the first example:

Kontextmenü von IntelliSense, in dem das @-Symbol eingegeben wurde und „HTML“, „Komponente“, „StatsService“ und „URL-Felder“ angezeigt werden

Die Standardfelder umfassen also Html, Component und Url sowie den StatsService-Dienst, den Sie eingefügt haben.As you can see, the default fields include Html, Component, and Url (as well as the StatsService that we injected). Wenn Sie beispielsweise die Standard-HTML-Hilfsprogramme durch ihre eigenen ersetzen möchten, können Sie dafür ganz einfach @inject verwenden: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>

Wenn Sie vorhandene Dienste erweitern möchten, können Sie diese Technik verwenden und aus der vorhanden Implementierung erben bzw. diese mit Ihrer eigenen umschließen.If you want to extend existing services, you can simply use this technique while inheriting from or wrapping the existing implementation with your own.

Weitere InformationenSee Also