學習新的開發寫法要投入時間,離開習慣的事物令人不安,因此轉移新版本或新平台過程總存在著無形阻力。此時常需要靠新版的某個迷人特性,才能讓你產生動力咬牙跨越圍籬。

像是 Interpolated Strings 字串插值,便是讓我積極改用 C# 6.0 的關鍵。至於 ASP.NET Core,MVC View 的 Razor 寫法與 ASP.NET MVC 5 差異不大(延伸閱讀:ASP.NET 簡史),但有個好物一直吸引我的目光 - Tag Helper (標籤協助程式)。

之前談 .js/.css 或圖檔 Cache 問題時有介紹過 Tag Helper,在 <script> 加上 app-append-version 自動產生 ?v=dLGP40S... 參數,當檔案內容修改 v 參數會自動改變,確保不會讀到舊版 Cache。這種在標準 HTML 標籤加上額外 Attribute 整合伺服端功能的概念,既能相容前端開發工具與習慣,又能結合後端 C# 邏輯,深得我心。

這篇文章就以大家熟悉的 MVC 5 欄位編輯網頁設計為例,介紹改用 Tag Helper 的新寫法。

直接借用 ASP.NET MVC 3 豬走路範例 (2)的 PlayerModel 資料型別,建立編輯玩家資料的 ASP.NET MVC 網頁。DemoController.cs 很簡單,Index Action 在 HttpGet 時純粹回傳 View,HttPost 時由前端接收 PlayerModel 型別,為示範 ValidationSummary 訊息呈現,故意用 ModelState.AddModelError() 加入錯誤:

using AspNetCore.Models;
using Microsoft.AspNetCore.Mvc;

namespace AspNetCore.Controllers
{
    public class DemoController : Controller
    {
        [HttpGet]
        public IActionResult Index()
        {
            return View();
        }
        [HttpPost]
        public IActionResult Index(PlayerModel player)
        {
            //加入不隸屬特定屬性的錯誤,顯示於ValidationSummary
            ModelState.AddModelError(
                string.Empty, "Test Error Message");
            return View();
        }
    }
}

Views/Demo/Index.cshtml 長這樣:

@model  AspNetCore.Models.PlayerModel
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>TagHelper Demo</title>
</head>
<body>
    @using (Html.BeginForm())
    {
        @Html.ValidationSummary(true)
        <fieldset>
            <legend>PlayerModel</legend>
            <dl>
                <dt>
                    @Html.LabelFor(m => m.Name)
                </dt>
                <dd>
                    @Html.EditorFor(m => m.Name)
                    @Html.ValidationMessageFor(m => m.Name)
                </dd>
                <dt>
                    @Html.LabelFor(m => m.Score)
                </dt>
                <dd>
                    @Html.EditorFor(m => m.Score)
                    @Html.ValidationMessageFor(m => m.Score)
                </dd>
            </dl>
            <p>
                <button>Create</button>
            </p>
        </fieldset>
    }
</body>
</html>

網頁效果如下:

看起來是蠻簡潔的,但對有前端開發經驗的人來說,雖然知道 @Html.LabelFor(m => m.Name) 在執行階段會轉成 HTML 標籤,LableFor() 方法也有 IDictionary<String,Object> htmlAttributes 參數 可加入 class、onclick 等配合前端設計的 Attribute,但永遠比不上直接寫 <label> 直覺。

為了提供更好的前端開發體驗,ASP.NET Core 加入了一些表單與輸入欄位用的 Tag Helper,允許開發者直接寫 HTML 標籤再透過 Tag Helper 由 Model 自動取得屬性顯示名稱、檢核規則設定,實現與 LabelFor()、EditorFor()、ValidationFor() 相似的效果,而開發者又能保有對 HTML 元素的完整掌控,兩全其美。

改用 Tag Helper 後欄位輸入 View 寫法如下:

@model  AspNetCore.Models.PlayerModel
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>TagHelper Demo</title>
</head>
<body>
    <form asp-controller="Demo" asp-action="Index" method="post">
        <div asp-validation-summary="ModelOnly"></div>
        <fieldset>
            <legend>PlayerModel</legend>
            <dl>
                <dt>
                    <label asp-for="Name"></label>
                </dt>
                <dd>
                    <input asp-for="Name" />
                    <span asp-validation-for="Name"></span>
                </dd>
                <dt>
                    <label asp-for="Score"></label>
                </dt>
                <dd>
                    <input asp-for="Score" />
                    <span asp-validation-for="Score"></span>
                </dd>
            </dl>
            <p>
                <button>Create</button>
            </p>
        </fieldset>
    </form>
</body>
</html>

值得一提的是,Visual Studio 2019 認得這些 Tag Helper,一樣有 Intellisense,例如 asp-for 要輸入屬性名稱時便會自動列出 Model 的所有屬性,體驗不錯。

比較 HtmlHelper 版本(左)與 Tag Helper 版本(右):

HTML 前端開發經驗較少的同學可能仍會偏好 HtmlHelper,可以少碰一些 HTML 標籤;但如果你熟悉前端開發或想完整控制 HTML 元素,絕對會愛上 Tag Helper。

兵器百百種,大家各取所好,用得順手最重要!

Introduction of ASP.NET Core's tag helpers for form.


Comments

# by Eagle

黑大不考慮前後端分離,前端改用Angular框架或是其他框架?

# by Jeffrey

to Eagle, 我寫過一陣子 SPA,但近年心得是 cshtml + 前端框架(我選了 Vue.js) MVVM + AJAX 與後端溝通的寫法最簡便快速。

# by Will

>> Visual Studio 2019 認得這些 Tag Helper,一樣有 Intellisense 想請教一下 Visual Studio Code 是不是就不支援 Intellisense

# by Jeffrey

to Will, VSCode 的功能來自各式各樣的外掛套件,基本的、常用的幾乎都有:https://marketplace.visualstudio.com/items?itemName=schneiderpat.aspnet-helper

Post a comment