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ż appsettings.Development.json
z przykładowego kodu:
{
"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 za pomocą dyrektywy @inject
.
@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 z wstrzykniętego StatisticsService
elementu. Ta usługa jest zarejestrowana do wstrzykiwania zależności w ConfigureServices
i 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 przechowywanej w pamięci. Implementacja w pamięci nie powinna być używana w przypadku dużych, zdalnych zestawów danych.
Próbka wyświetla dane z modelu, który jest powiązany z widokiem, i z usługi wstrzykniętej do widoku.
Wypełnianie danych wyszukiwania
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 do wyświetlenia formularza edycji profilu musi jedynie przekazać formularzowi wystąpienie 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:
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>
Usługa ProfileOptionsService
to usługa 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 niezarejestrowany typ zgłasza wyjątek w czasie wykonywania, ponieważ dostawca usług jest wewnętrznie odpytywany za pośrednictwem 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:
Pola domyślne obejmują Html
, Component
i 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ż
- Simon Timms Blog: Pobieranie danych referencyjnych do widoku
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ć rozdzielenie obowiązków między kontrolerami i widokami. Większość danych wyświetlanych w widokach 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 @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 dyrektywy @inject
. Możesz traktować @inject
jako dodanie właściwości do widoku i wypełnianie jej używając 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 StatisticsService
elementu. Ta usługa jest zarejestrowana do wstrzykiwania zależności w ConfigureServices
i 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:
Wypełnianie danych odwołań
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, która wyświetla formularz edycji profilu, musi jedynie przekazać formularzowi instancję 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:
Te listy są wypełniane przez usługę, która została zintegrowana 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>
To ProfileOptionsService
to usługa na poziomie UI 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 niezarejestrowany zgłasza wyjątek w czasie wykonywania, ponieważ dostawca usług jest wewnętrznie zapytany 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:
Jak widać, pola domyślne obejmują Html
, Component
i 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, dziedzicząc od lub owijając istniejącą implementację swoimi własnymi rozwiązaniami.
Zobacz też
- Simon Timms Blog: Pobieranie danych pomocniczych do widoku