Delen via


Afhankelijkheidsinjectie in weergaven in ASP.NET Core

ASP.NET Core ondersteunt afhankelijkheidsinjectie in views. Dit kan handig zijn voor weergavespecifieke services, zoals lokalisatie of gegevens die alleen nodig zijn voor het invullen van weergave-elementen. De meeste weergaven van gegevens moeten worden doorgegeven vanuit de controller.

voorbeeldcode bekijken of downloaden (hoe te downloaden)

Configuratie-injectie

De waarden in instellingenbestanden, zoals appsettings.json en appsettings.Development.json, kunnen in een weergave worden geïnjecteerd. Bekijk de appsettings.Development.json uit de voorbeeldcode:

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

De volgende markup geeft de configuratiewaarde weer in een Razor Pagina's-weergave.

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

In de volgende markeringen wordt de configuratiewaarde weergegeven in een MVC-weergave:

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

Zie Configuratie in ASP.NET Core- voor meer informatie

Service-injectie

Een service kan worden geïnjecteerd in een weergave met behulp van de @inject-instructie.

@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 deze weergave wordt een lijst met ToDoItem exemplaren weergegeven, samen met een samenvatting met algemene statistieken. De samenvatting wordt gegenereerd uit de geïnjecteerde StatisticsService. Deze service is geregistreerd voor afhankelijkheidsinjectie 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();

De StatisticsService voert enkele berekeningen uit op de set ToDoItem instanties, die het benadert via een opslagplaats.

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

De voorbeeldopslagplaats maakt gebruik van een in-memory verzameling. Een in-memory implementatie mag niet worden gebruikt voor grote, extern geopende gegevenssets.

In het voorbeeld worden gegevens van het model weergegeven dat is gebonden aan de weergave en de service die in de weergave is geïnjecteerd:

Voorbeeld van de To Do-lijst, inclusief totaalitems, voltooide items, gemiddelde prioriteit, en een lijst met taken met hun prioriteitsniveaus en waarden die voltooiing aangeven.

Opzoekgegevens invullen

Weergave-injectie kan handig zijn om opties in UI-elementen te vullen, zoals vervolgkeuzelijsten. Overweeg een gebruikersprofielformulier met opties voor het opgeven van geslacht, status en andere voorkeuren. Het weergeven van een dergelijk formulier met behulp van een standaardbenadering vereist mogelijk dat de controller of Razor Page het volgende moet doen:

  • Services voor gegevenstoegang aanvragen voor elk van de sets met opties.
  • Vul een model of ViewBag met elke set opties die moeten worden gebonden.

Een alternatieve benadering injecteert diensten rechtstreeks in de weergave om de opties te verkrijgen. Dit minimaliseert de hoeveelheid code die nodig is voor de controller of razor Page, zodat deze logica voor de bouw van weergave-elementen naar de weergave zelf wordt verplaatst. De actie van de controller of de Razor pagina om een bewerkingsformulier voor een profiel weer te geven hoeft alleen het formulier door te geven aan het profielvoorbeeld.

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

Het HTML-formulier dat wordt gebruikt om de voorkeuren bij te werken, bevat vervolgkeuzelijsten voor drie van de eigenschappen:

Profielweergave bijwerken met een formulier waarmee de naam, het geslacht, de status en de favoriete kleur kunnen worden opgegeven.

Deze lijsten worden ingevuld door een service die is geïnjecteerd in de weergave:

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

De ProfileOptionsService is een service op gebruikersinterfaceniveau die is ontworpen om alleen de gegevens te bieden die nodig zijn voor dit formulier:

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

Houd er rekening mee dat een niet-geregistreerd type tijdens runtime een uitzondering genereert omdat de serviceprovider intern wordt opgevraagd via GetRequiredService.

Services overschakelen

Naast het injecteren van nieuwe services, kan deze techniek worden gebruikt om eerder geïnjecteerde services op een pagina te overschrijven. In de onderstaande afbeelding ziet u alle velden die beschikbaar zijn op de pagina die in het eerste voorbeeld wordt gebruikt:

contextmenu van IntelliSense in een getypt @-symbool met de velden Html, Component, StatsService en URL

De standaardvelden bevatten Html, Componenten Url. Gebruik @injectom de standaard HTML-helpers te vervangen door een aangepaste versie:

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

Zie ook

ASP.NET Core ondersteunt afhankelijkheidsinjectie in weergaven. Dit kan handig zijn voor weergavespecifieke services, zoals lokalisatie of gegevens die alleen nodig zijn voor het invullen van weergave-elementen. Je moet proberen scheiding van verantwoordelijkheden tussen je controllers en weergaven te behouden. De meeste gegevens die worden weergegeven, moeten worden doorgegeven vanuit de controller.

voorbeeldcode weergeven of downloaden (hoe te downloaden)

Configuratie-injectie

appsettings.json waarden kunnen rechtstreeks in een weergave worden geïnjecteerd.

Voorbeeld van een appsettings.json-bestand:

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

De syntaxis voor @inject: @inject <type> <name>

Een voorbeeld met @inject:

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

Service-injectie

Een service kan worden geïnjecteerd in een weergave met behulp van de @inject-instructie. U kunt @inject zien als het toevoegen van een eigenschap aan de weergave en het invullen van de eigenschap met behulp van 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 deze weergave wordt een lijst met ToDoItem exemplaren weergegeven, samen met een samenvatting met algemene statistieken. De samenvatting wordt ingevuld vanuit de geïnjecteerde StatisticsService. Deze service is geregistreerd voor afhankelijkheidsinjectie 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();

De StatisticsService voert enkele berekeningen uit op de set ToDoItem instanties, die via een repository worden benaderd.

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

De voorbeeldopslagplaats maakt gebruik van een in-memory verzameling. De hierboven weergegeven implementatie (die op alle gegevens in het geheugen werkt) wordt niet aanbevolen voor grote, extern geopende gegevenssets.

In het voorbeeld worden gegevens van het model weergegeven dat is gebonden aan de weergave en de service die in de weergave is geïnjecteerd:

Overzicht van To Do-items inclusief totaal aantal, voltooide items, gemiddelde prioriteitsniveau, en een takenlijst met hun prioriteitsniveaus en booleaanse waarden die voltooiing aangeven.

Opzoekgegevens invullen

Weergave-injectie kan handig zijn om opties in UI-elementen te vullen, zoals vervolgkeuzelijsten. Overweeg een gebruikersprofielformulier met opties voor het opgeven van geslacht, status en andere voorkeuren. Voor het weergeven van een dergelijk formulier met behulp van een standaard MVC-benadering moet de controller gegevenstoegangsservices voor elk van deze sets opties aanvragen en vervolgens een model of ViewBag vullen met elke set opties die moeten worden gebonden.

Een alternatieve benadering injecteert services rechtstreeks in de weergave om de opties te verkrijgen. Dit minimaliseert de hoeveelheid code die door de controller is vereist, en verplaatst deze logica voor de constructie van weergave-elementen naar de weergave zelf. De controlleractie voor het weergeven van een profielbewerkingsformulier hoeft alleen het profielexemplaar mee te geven aan het formulier.

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

Het HTML-formulier dat wordt gebruikt om deze voorkeuren bij te werken, bevat vervolgkeuzelijsten voor drie van de eigenschappen:

Profielweergave bijwerken met een formulier waarmee de naam, het geslacht, de status en de favoriete kleur kunnen worden opgegeven.

Deze lijsten worden ingevuld door een service die is geïnjecteerd in de weergave:

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

De ProfileOptionsService is een service op gebruikersinterfaceniveau die is ontworpen om alleen de gegevens te bieden die nodig zijn voor dit formulier:

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

Belangrijk

Vergeet niet om de typen die u via afhankelijkheidsinjectie aanvraagt, te registreren in Startup.ConfigureServices. Een niet-geregistreerd type genereert tijdens runtime een uitzondering omdat de serviceprovider intern wordt opgevraagd via GetRequiredService.

Services overschrijven

Naast het injecteren van nieuwe services, kan deze techniek ook worden gebruikt om eerder geïnjecteerde services op een pagina te overschrijven. In de onderstaande afbeelding ziet u alle velden die beschikbaar zijn op de pagina die in het eerste voorbeeld wordt gebruikt:

contextmenu van IntelliSense in een getypt @-symbool met de velden Html, Component, StatsService en URL

Zoals u kunt zien, bevatten de standaardvelden Html, Componenten Url (evenals de StatsService die we hebben geïnjecteerd). Als u bijvoorbeeld de standaard HTML Helpers wilt vervangen door uw eigen HTML-helpers, kunt u dit eenvoudig doen met behulp van @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>

Als u bestaande services wilt uitbreiden, kunt u deze techniek gewoon gebruiken tijdens het overnemen van of verpakken van de bestaande implementatie met uw eigen implementatie.

Zie ook