ASP.NET Core 檢視中的相依性插入
ASP.NET Core 支援檢視中的相依性插入。 這可用於檢視特定服務,例如僅適用於填入檢視項目所需的當地語系化或資料。 檢視所顯示的大部分資料都應該從控制器傳入。
檢視或下載範例程式碼 \(英文\) (如何下載)
插入組態
設定檔中的值,例如 appsettings.json
和 appsettings.Development.json
,可以插入檢視中。 考慮來自範例程式碼的 appsettings.Development.json
:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"MyRoot": {
"MyParent": {
"MyChildName": "Joe"
}
}
}
下列標記會在 Razor 網頁檢視中顯示設定值:
@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>
下列標記會在 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>
如需詳細資訊,請參閱 ASP.NET Core 中的設定
插入服務
使用 @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>
此檢視會顯示 ToDoItem
執行個體清單,以及顯示整體統計資料的摘要。 摘要是從插入的 StatisticsService
中填入。 此服務已在 Program.cs
的 ConfigureServices
中註冊相依性插入:
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
會對一組 ToDoItem
執行個體執行一些計算,以透過存放庫進行存取:
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);
}
}
}
範例存放庫會使用記憶體內部集合。 記憶體內部實作不應該用於大型、遠端存取的資料集。
此範例所顯示的資料來自繫結至檢視的模型,以及插入至檢視的服務:
填入查閱資料
檢視插入可以用來填入 UI 項目中的選項,例如下拉式清單。 請考慮使用者設定檔表單,其中包含指定性別、狀態和其他喜好設定的選項。 使用標準方法轉譯這類表單可能需要控制器或 Razor 頁面,才能:
- 針對每組選項要求資料存取服務。
- 使用要繫結的每組選項填入模型或
ViewBag
。
另一種方法會將服務直接插入至檢視,以取得選項。 這會將控制器或 razor 頁面所需的程式碼數量降到最低,並將此檢視元素建構邏輯移至檢視本身。 要顯示設定檔編輯表單的控制器動作或 Razor 頁面,只需要將設定檔執行個體傳遞給表單:
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 表單包含三個屬性的下拉式清單:
這些清單會填入已插入至檢視的服務:
@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
是設計成只提供此表單所需資料的 UI 層級服務:
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" };
}
}
請注意,未註冊的類型會在執行階段擲回例外狀況,因為服務提供者是透過 GetRequiredService 進行內部查詢。
覆寫服務
除了插入新的服務之外,這項技術可以用來覆寫頁面上先前插入的服務。 下圖顯示第一個範例中所使用頁面上的所有可用欄位:
預設欄位包括 Html
、Component
和 Url
。 若要以自訂版本取代預設 HTML 協助程式,請使用 @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>
另請參閱
- Simon Timms 部落格:將查閱資料放入檢視中
ASP.NET Core 支援檢視中的相依性插入。 這可用於檢視特定服務,例如僅適用於填入檢視項目所需的當地語系化或資料。 您應該嘗試維護控制器與檢視之間的 Separation of Concerns (關注點分離)。 您檢視所顯示的大部分資料應該都是從控制器傳入。
檢視或下載範例程式碼 \(英文\) (如何下載)
插入組態
appsettings.json
值可以直接插入檢視中。
appsettings.json
檔案的範例:
{
"root": {
"parent": {
"child": "myvalue"
}
}
}
@inject
的語法:@inject <type> <name>
使用 @inject
的範例:
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
@{
string myValue = Configuration["root:parent:child"];
...
}
插入服務
使用 @inject
指示詞,可將服務插入至檢視。 您可以將 @inject
視為將屬性新增至檢視,並使用 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>
此檢視會顯示 ToDoItem
執行個體清單,以及顯示整體統計資料的摘要。 摘要是從插入的 StatisticsService
中填入。 此服務已在 Startup.cs
的 ConfigureServices
中註冊相依性插入:
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
會對一組 ToDoItem
執行個體執行一些計算,以透過存放庫進行存取:
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);
}
}
}
範例存放庫會使用記憶體內部集合。 上面顯示的實作 (作用於記憶體中的所有資料) 不建議用於大型可從遠端存取的資料集。
此範例所顯示的資料來自繫結至檢視的模型,以及插入至檢視的服務:
填入查閱資料
檢視插入可以用來填入 UI 項目中的選項,例如下拉式清單。 請考慮使用者設定檔表單,其中包含指定性別、狀態和其他喜好設定的選項。 使用標準 MVC 方法轉譯這類表單時,需要控制器要求所有這些選項集的資料存取服務,然後將已繫結的每個選項集填入模型或 ViewBag
中。
另一種方法會將服務直接插入至檢視,以取得選項。 這會將控制器所需的程式碼數量降到最低,並將此檢視項目建構邏輯移至檢視本身。 要顯示設定檔編輯表單的控制器動作,只需要將設定檔執行個體傳遞給表單:
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 表單包括三個屬性的下拉式清單:
這些清單會填入已插入至檢視的服務:
@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
是設計成只提供此表單所需資料的 UI 層級服務:
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" };
}
}
}
重要
請不要忘記在 Startup.ConfigureServices
中註冊您透過相依性插入所要求的類型。 未註冊的類型會在執行階段擲回例外狀況,因為服務提供者是透過 GetRequiredService 進行內部查詢。
覆寫服務
除了插入新的服務之外,這項技術也可以用來覆寫頁面上先前插入的服務。 下圖顯示第一個範例中所使用頁面上的所有可用欄位:
如您所見,預設欄位包括 Html
、Component
和 Url
(以及我們插入的 StatsService
)。 例如,如果您要將預設 HTML 協助程式取代為您自己的協助程式,則使用 @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>
如果您想要擴充現有服務,則只需要在繼承自現有實作或自行包裝現有實作時使用這項技術。
另請參閱
- Simon Timms 部落格:將查閱資料放入檢視中