ASP.NET Core 中文文檔 第四章 MVC(3.8)視圖中的依賴注入


原文:Dependency injection into views
作者:Steve Smith
翻譯:姚阿勇(Dr.Yao)
校對:孟帥洋(書緣)

ASP.NET Core 支持在視圖中使用 依賴注入 。這將有助於提供視圖專用的服務,比如本地化或者僅用於填充視圖元素的數據。你應該盡量保持控制器和視圖間的關注點分離(separation of concerns)。你的視圖所顯示的大部分數據應該從控制器傳入。

章節:

查看或下載示例源碼

一個簡單的示例

你可以使用 @inject 指令將服務注入到視圖中。可以把 @inject 看作是給你的視圖增加一個屬性,然后利用依賴注入給這個屬性賦值。

@inject 的語法:
@inject <type> <name>

一個使用 @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 填入的。這個服務是在 Startup.cs 里的 ConfigureServices 方法中被注冊到依賴注入項的。

// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddTransient<IToDoItemRepository, ToDoItemRepository>();
    services.AddTransient<StatisticsService>();
    services.AddTransient<ProfileOptionsService>();

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

示例中的倉儲使用的是 in-memory 集合。上面的實現方法(所有對內存數據的操作)不推薦用於大型、遠程存儲的數據集。

這個示例通過綁定到視圖的模型以及注入到視圖的服務來顯示數據:

填充查找數據

視圖注入有助於填充 UI 元素中的選項數據,例如下拉列表。設想一個包括性別、州以及其他選項的用戶資料表單。如果通過標准的 MVC 方式渲染這樣一個表單,需要控制器為每一組選項都請求數據訪問服務,然后將每一組待綁定的選項填充到模型或 ViewBag 中。

另一種方法則直接將服務注入到視圖中以獲取這些選項數據。這種方法將控制器需要的代碼量減到了最少,把構造視圖元素的邏輯移到視圖本身中去。用來顯示資料編輯表單的控制器 Action 只需要把用戶資料實例傳給表格就可以了(而不需要傳各種選項數據,譯注):

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.csConfigureServices 方法中把你想要通過依賴注入請求的類型注冊一下。

重寫服務

除了注入新服務之外,這種技術也可以用來重寫之前已經在頁面上注入的服務。下圖顯示了在第一個例子的頁面上可用的所有字段:

如你所見,默認的字段有 HtmlComponentUrl (同樣還有我們注入的 StatsService)。假如你想要把默認的 HTML Helpers 替換成你自己的,你可以利用 @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>

如果你想要擴展已有服務,你只需要在使用這種替換技術的同時,讓你自己的服務繼承或封裝已有實現。

參考

返回目錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM