Beroendeinmatning i vyer i ASP.NET Core
ASP.NET Core stöder beroendeinmatning i vyer. Detta kan vara användbart för visningsspecifika tjänster, till exempel lokalisering eller data som endast krävs för att fylla i vyelement. De flesta datavyer som visas ska skickas in från kontrollanten.
Visa eller ladda ned exempelkod (hur du laddar ned)
Konfigurationsinjektion
Värdena i inställningsfiler, till exempel appsettings.json
och appsettings.Development.json
, kan matas in i en vy. Överväg appsettings.Development.json
från exempelkod:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"MyRoot": {
"MyParent": {
"MyChildName": "Joe"
}
}
}
Följande markering visar konfigurationsvärdet i vyn Razor Pages:
@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>
Följande markering visar konfigurationsvärdet i en MVC-vy:
@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>
Mer information finns i Configuration i ASP.NET Core
Tjänsteinjektion
En tjänst kan matas in i en vy med hjälp av @inject
-direktivet.
@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>
Den här vyn visar en lista över ToDoItem
instanser, tillsammans med en sammanfattning som visar övergripande statistik. Sammanfattningen fylls i från den inmatade StatisticsService
. Den här tjänsten är registrerad för beroendeinmatning i 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();
StatisticsService
utför vissa beräkningar på uppsättningen ToDoItem
instanser som den kommer åt via en lagringsplats:
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);
}
}
}
Exempeldatabasen använder en minnesintern samling. En minnesintern implementering bör inte användas för stora, fjärranslutna datauppsättningar.
Exemplet visar data från modellen som är bunden till vyn och tjänsten som matas in i vyn:
Fylla i uppslagsdata
Vyinsprutning kan vara användbart för att fylla i val i lister över användargränssnittselement, till exempel rullgardinsmenyer. Överväg ett användarprofilformulär som innehåller alternativ för att ange kön, tillstånd och andra inställningar. Återgivning av ett sådant formulär med en standardmetod kan kräva att kontrollanten eller Razor-sidan:
- Begär dataåtkomsttjänster för var och en av alternativen.
- Fyll i en modell eller
ViewBag
med varje uppsättning alternativ som ska bindas.
En alternativ metod matar in tjänster direkt i vyn för att få alternativen. Detta minimerar mängden kod som krävs av kontrollen eller Razor-sidan och flyttar denna logik för konstruktion av visningselement till själva vyn. Kontrollantåtgärden eller Razor sidan för att visa ett profilredigeringsformulär behöver bara skicka formuläret till profilinstansen:
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);
}
}
HTML-formuläret som används för att uppdatera inställningarna innehåller listrutor för tre av egenskaperna:
De här listorna fylls i av en tjänst som har integrerats med vyn.
@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
är en tjänst på användargränssnittsnivå som är utformad för att bara tillhandahålla de data som behövs för det här formuläret:
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" };
}
}
Observera att en oregistrerad typ utlöser ett undantag vid körning eftersom tjänstleverantören frågas internt via GetRequiredService.
Åsidosättande tjänster
Förutom att mata in nya tjänster kan den här tekniken användas för att åsidosätta tidigare inmatade tjänster på en sida. Bilden nedan visar alla fält som är tillgängliga på sidan som används i det första exemplet:
Standardfälten innehåller Html
, Component
och Url
. Om du vill ersätta HTML-standardhjälparna med en anpassad version använder du @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>
Se även
- Simon Timms blogg: Att få in uppslagsdata i din vy
ASP.NET Core stöder beroendeinmatning i vyer. Detta kan vara användbart för visningsspecifika tjänster, till exempel lokalisering eller data som endast krävs för att fylla i vyelement. Du bör försöka upprätthålla separation av ansvar mellan dina kontroller och vyer. De flesta av de data som dina vyer visar bör skickas in från kontrollern.
Visa eller ladda ned exempelkod (hur du laddar ned)
Konfigurationsinjektion
appsettings.json
-värden kan injiceras direkt i en vy.
Exempel på en appsettings.json
fil:
{
"root": {
"parent": {
"child": "myvalue"
}
}
}
Syntaxen för @inject
: @inject <type> <name>
Ett exempel med @inject
:
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
@{
string myValue = Configuration["root:parent:child"];
...
}
Serviceinjektion
En tjänst kan matas in i en vy med hjälp av @inject
-direktivet. Du kan tänka dig @inject
som att lägga till en egenskap i vyn och fylla i egenskapen med 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>
Den här vyn visar en lista över ToDoItem
instanser, tillsammans med en sammanfattning som visar övergripande statistik. Sammanfattningen fylls i från den inmatade StatisticsService
. Den här tjänsten är registrerad för beroendeinjicering i 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();
StatisticsService
utför vissa beräkningar på uppsättningen ToDoItem
instanser som den kommer åt via en lagringsplats:
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);
}
}
}
Exempellagringsplatsen använder en minnesintern samling. Implementeringen som visas ovan (som fungerar på alla data i minnet) rekommenderas inte för stora, fjärranslutna datauppsättningar.
Exemplet visar data från modellen som är bunden till vyn och tjänsten som matas in i vyn:
Fylla i uppslagsdata
Vyinjektion kan vara användbart för att fylla i alternativ i gränssnittselement, till exempel listrutor. Överväg ett användarprofilformulär som innehåller alternativ för att ange kön, tillstånd och andra inställningar. Om ett sådant formulär återges med en standardmetod för MVC skulle kontrollanten begära dataåtkomsttjänster för var och en av dessa uppsättningar alternativ och sedan fylla i en modell eller ViewBag
med varje uppsättning alternativ som ska bindas.
En alternativ metod matar in tjänster direkt i vyn för att få alternativen. Detta minimerar mängden kod som krävs av kontrollanten och flyttar den här vyns elementkonstruktionslogik till själva vyn. Kontrollantåtgärden för att visa ett profilredigeringsformulär behöver bara skicka formuläret till profilinstansen:
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);
}
}
}
HTML-formuläret som används för att uppdatera dessa inställningar innehåller listrutor för tre av egenskaperna:
De här listorna fylls i av en tjänst som har infogats i vyn.
@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
är en tjänst på användargränssnittsnivå som är utformad för att bara tillhandahålla de data som behövs för det här formuläret:
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" };
}
}
}
Viktig
Glöm inte att registrera typer du begär via beroendeinjektion i Startup.ConfigureServices
. En oregistrerad typ utlöser ett undantag vid körning eftersom tjänstleverantören förfrågas internt via GetRequiredService.
Åsidosättande tjänster
Förutom att mata in nya tjänster kan den här tekniken också användas för att åsidosätta tidigare inmatade tjänster på en sida. Bilden nedan visar alla fält som är tillgängliga på sidan som används i det första exemplet:
Som du ser innehåller standardfälten Html
, Component
och Url
(samt de StatsService
som vi har matat in). Om du till exempel vill ersätta HTML-standardhjälparna med dina egna kan du enkelt göra det med hjälp av @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>
Om du vill utöka befintliga tjänster kan du helt enkelt använda den här tekniken när du ärver från eller omsluter den befintliga implementeringen med din egen.
Se även
- Simon Timms Blogg: hämta uppslagsdata till din vy
ASP.NET Core