Wstrzykiwanie zależności do widoków w programie ASP.NET Core

ASP.NET Core obsługuje wstrzykiwanie zależności do widoków. Może to być przydatne w przypadku usług specyficznych dla widoku, takich jak lokalizacja lub dane wymagane tylko do wypełniania elementów widoku. Większość wyświetlanych widoków danych powinna zostać przekazana z kontrolera.

Wyświetl lub pobierz przykładowy kod (jak pobrać)

Iniekcja konfiguracji

Wartości w plikach ustawień, takich jak appsettings.json i appsettings.Development.json, można wstrzykiwać do widoku. Rozważ użycie appsettings.Development.json kodu przykładowego:

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

Poniższy znacznik wyświetla wartość konfiguracji w Razor widoku Strony:

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

Poniższy znacznik wyświetla wartość konfiguracji w widoku MVC:

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

Aby uzyskać więcej informacji, zobacz Configuration in ASP.NET Core (Konfiguracja w programie ASP.NET Core)

Wstrzykiwanie usługi

Usługę można wstrzyknąć do widoku przy użyciu @inject dyrektywy .

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

Ten widok zawiera listę ToDoItem wystąpień wraz z podsumowaniem przedstawiającym ogólne statystyki. Podsumowanie jest wypełniane ze wstrzykniętego StatisticsServiceelementu . Ta usługa jest zarejestrowana do wstrzykiwania zależności w programie ConfigureServices w programie 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();

Funkcja StatisticsService wykonuje pewne obliczenia na zestawie ToDoItem wystąpień, do których uzyskuje dostęp za pośrednictwem repozytorium:

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

Przykładowe repozytorium używa kolekcji w pamięci. Implementacja w pamięci nie powinna być używana w przypadku dużych, zdalnych zestawów danych.

Przykład wyświetla dane z modelu powiązanego z widokiem i usługą wstrzykniętą do widoku:

To Do view listing total items, completed items, average priority, and a list of tasks with their priority levels and boolean values indicating completion.

Wypełnianie danych odnośników

Iniekcja widoku może być przydatna do wypełniania opcji w elementach interfejsu użytkownika, takich jak listy rozwijane. Rozważ formularz profilu użytkownika zawierający opcje określania płci, stanu i innych preferencji. Renderowanie takiego formularza przy użyciu standardowego podejścia może wymagać, aby kontroler lub Razor strona:

  • Żądanie usług dostępu do danych dla każdego zestawu opcji.
  • Wypełnij model lub ViewBag przy użyciu każdego zestawu opcji, które mają być powiązane.

Alternatywne podejście wprowadza usługi bezpośrednio do widoku w celu uzyskania opcji. Minimalizuje to ilość kodu wymaganego przez kontroler lub stronę razor, przenosząc logikę budowy tego elementu widoku do samego widoku. Akcja kontrolera lub Razor strona, aby wyświetlić formularz edycji profilu, musi przekazać tylko formularz wystąpienia profilu:

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

Formularz HTML używany do aktualizowania preferencji zawiera listy rozwijane dla trzech właściwości:

Update Profile view with a form allowing the entry of name, gender, state, and favorite Color.

Te listy są wypełniane przez usługę, która została wstrzyknięta do widoku:

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

Jest ProfileOptionsService to usługa na poziomie interfejsu użytkownika zaprojektowana tak, aby dostarczać tylko dane potrzebne do tego formularza:

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

Zwróć uwagę, że typ wyrejestrowany zgłasza wyjątek w czasie wykonywania, ponieważ dostawca usług jest wewnętrznie odpytywany za pośrednictwem polecenia GetRequiredService.

Zastępowanie usług

Oprócz wstrzykiwania nowych usług ta technika może służyć do zastępowania wcześniej wstrzykiwanych usług na stronie. Na poniższej ilustracji przedstawiono wszystkie pola dostępne na stronie użyte w pierwszym przykładzie:

Intellisense contextual menu on a typed @ symbol listing Html, Component, StatsService, and Url fields

Pola domyślne obejmują Html, Componenti Url. Aby zastąpić domyślnych pomocników HTML niestandardową wersją, użyj polecenia @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>

Zobacz też

ASP.NET Core obsługuje wstrzykiwanie zależności do widoków. Może to być przydatne w przypadku usług specyficznych dla widoku, takich jak lokalizacja lub dane wymagane tylko do wypełniania elementów widoku. Należy starać się zachować separację problemów między kontrolerami i poglądami . Większość danych wyświetlanych widoków powinna zostać przekazana z kontrolera.

Wyświetl lub pobierz przykładowy kod (jak pobrać)

Iniekcja konfiguracji

appsettings.json wartości można wstrzykiwać bezpośrednio do widoku.

appsettings.json Przykład pliku:

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

Składnia dla elementu @inject: @inject <type> <name>

Przykład z użyciem polecenia @inject:

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

Wstrzykiwanie usługi

Usługę można wstrzyknąć do widoku przy użyciu @inject dyrektywy . Możesz traktować @inject jako dodawanie właściwości do widoku i wypełnianie właściwości przy użyciu 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>

Ten widok zawiera listę ToDoItem wystąpień wraz z podsumowaniem przedstawiającym ogólne statystyki. Podsumowanie jest wypełniane ze wstrzykniętego StatisticsServiceelementu . Ta usługa jest zarejestrowana do wstrzykiwania zależności w programie ConfigureServices w programie 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();

Funkcja StatisticsService wykonuje pewne obliczenia na zestawie ToDoItem wystąpień, do których uzyskuje dostęp za pośrednictwem repozytorium:

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

Przykładowe repozytorium używa kolekcji w pamięci. Implementacja pokazana powyżej (która działa na wszystkich danych w pamięci) nie jest zalecana w przypadku dużych, zdalnych zestawów danych.

Przykład wyświetla dane z modelu powiązanego z widokiem i usługą wstrzykniętą do widoku:

To Do view listing total items, completed items, average priority, and a list of tasks with their priority levels and boolean values indicating completion.

Wypełnianie danych odnośników

Iniekcja widoku może być przydatna do wypełniania opcji w elementach interfejsu użytkownika, takich jak listy rozwijane. Rozważ formularz profilu użytkownika zawierający opcje określania płci, stanu i innych preferencji. Renderowanie takiego formularza przy użyciu standardowego podejścia MVC wymagałoby od kontrolera żądania usług dostępu do danych dla każdego z tych zestawów opcji, a następnie wypełnienia modelu lub ViewBag każdego zestawu opcji, które mają być powiązane.

Alternatywne podejście wprowadza usługi bezpośrednio do widoku w celu uzyskania opcji. Minimalizuje to ilość kodu wymaganego przez kontroler, przenosząc logikę budowy tego elementu widoku do samego widoku. Akcja kontrolera w celu wyświetlenia formularza edycji profilu musi jedynie przekazać formularz wystąpienia profilu:

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

Formularz HTML używany do aktualizowania tych preferencji zawiera listy rozwijane dla trzech właściwości:

Update Profile view with a form allowing the entry of name, gender, state, and favorite Color.

Te listy są wypełniane przez usługę, która została wstrzyknięta do widoku:

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

Jest ProfileOptionsService to usługa na poziomie interfejsu użytkownika zaprojektowana tak, aby dostarczać tylko dane potrzebne do tego formularza:

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

Ważne

Nie zapomnij zarejestrować typów, których żądasz za pomocą iniekcji zależności w programie Startup.ConfigureServices. Typ wyrejestrowany zgłasza wyjątek w czasie wykonywania, ponieważ dostawca usług jest wewnętrznie odpytywany za pośrednictwem metody GetRequiredService.

Zastępowanie usług

Oprócz wstrzykiwania nowych usług ta technika może również służyć do zastępowania wcześniej wstrzykiwanych usług na stronie. Na poniższej ilustracji przedstawiono wszystkie pola dostępne na stronie użyte w pierwszym przykładzie:

Intellisense contextual menu on a typed @ symbol listing Html, Component, StatsService, and Url fields

Jak widać, pola domyślne obejmują Html, Componenti Url (a także StatsService wprowadzone przez nas pola). Jeśli na przykład chcesz zastąpić domyślnych pomocników HTML własnymi, możesz to łatwo zrobić przy użyciu polecenia @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>

Jeśli chcesz rozszerzyć istniejące usługi, możesz po prostu użyć tej techniki podczas dziedziczenia z lub opakowywania istniejącej implementacji własnymi.

Zobacz też