前言
為了這一篇,前面需要鋪了許多的梗,寫了許多可能不是很重要但很基礎的觀念,包含- Html 基礎 (請參考 網頁系統 與 Html基礎簡介)
- Controller, Action 與 View 的關係(請參考 Controller and View 1-3)。
- Razor, html Helper, 與model binder (請參考 Razor and Htmlhelper)
若有觀念錯誤與修改建議,也請各位先進不吝指教。
介紹
在Controller and View 2 - 資料傳遞篇,我們有提到簡易的接收與傳遞資料的方法,但隨著系統功能複雜與欄位越來越多的情況下,我們的資料內容也越來越多,而必須增加許
多程式碼做介接與驗證,維護變得相當不容易。
一般來說,許多程式開發者會使用(Data transfer object, DTO)的方式來處理這個問題。
將所有的參數放入一個物件裡,進行傳遞,好處是增加程式的可讀性與容易使用。
回想起剛開始學習 MVC 的時候,不懂ViewModel的目的與用途,而一直將他視作DTO
並用來傳遞參數,但隨著開發時間久了,雖然覺得ViewModel與DTO頗相似,但個人覺
得比ViewModel 較接近於描述 View 的行為或定義 View 的規格。
簡單的例子:
使用者資料維護功能,CreateUserViewModel 與 UpdateUserPasswordViewModel 內容來
源都是使用者資料庫,但 UpdateUserPasswordViewModel 內可能只有使用者帳號與密碼
相關欄位,而不需要將所有資料帶出。
另外,ViewModel也能透過增加屬性的方式,進行資料格式指定與驗證,所以個人認知
偏向 ViewModel 用於描述 View 的規格。
要如何設計一個ViewModel,對於第一次建立的同學,我們建議兩個方法:
- 資料長怎樣,就怎麼設計。
- View 需要什麼資料,就怎麼設計。
- 學號
- 姓名
- 班級
- 通訊地址
- 電子郵件
- 連絡電話
首先,先右鍵選取 Project -> add -> add folder ,命名為ViewModel
在 ViewModel 資料夾點選右鍵 -> Add item...
選擇Code -> Class,取名為CreateStudentViewModel.cs,點選Add
修改 CreateStudentViewModel.cs 如以下程式:
namespace WebApplication1.ViewModel { public class CreateStudentViewModel { public string ID { get; set; } public string NAME { get; set; } public string ADDRESS { get; set; } public string EMAIL { get; set; } public string TEL { get; set; } } }
我們在HomeController,建立兩個Create action,如下所示:
public ActionResult Create() { CreateStudentViewModel model = new CreateStudentViewModel(); return View(model); } [HttpPost] public ActionResult Create(CreateStudentViewModel model) { return View(model); }
第一個 Public Action Result Create()
使用者第一次進入學生資料建立畫面的時候,不會帶入任何參數。但我們必須初始化
CreateStudentViewModel,並且傳遞進入View提供使用。(若不初始化,View 使用
model binder取得Model資料時,會產生null exception)
第二個public ActionResult Create(CreateStudentViewModel model)
當使用者輸入資料後點選送出,我們接收CreateStudentViewModel的資料,進行邏輯運算。
(可能是驗證、新增資料或計算動作...等)
接下來,我們對 Create action 點選右鍵 -> Add View... 建立View
在 View 最上方,我們要先宣告ViewModel的格式
@model WebApplication1.ViewModel.CreateStudentViewModel
我們將 View 內容改成如下
@model WebApplication1.ViewModel.CreateStudentViewModel @{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (Html.BeginForm("Create", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { @Html.AntiForgeryToken() @Html.ValidationSummary(true, "", new { }) <table> <tr> <th>@Html.LabelFor(model => model.ID)</th> <td> @Html.TextBoxFor(model => model.ID) @Html.ValidationMessageFor(model => model.ID, "", new {}) </td> </tr> <tr> <th>@Html.LabelFor(model => model.NAME)</th> <td> @Html.TextBoxFor(model => model.NAME) @Html.ValidationMessageFor(model => model.NAME, "", new { }) </td> </tr> <tr> <th>@Html.LabelFor(model => model.EMAIL)</th> <td> @Html.TextBoxFor(model => model.EMAIL) @Html.ValidationMessageFor(model => model.EMAIL, "", new { }) </td> </tr> <tr> <th>@Html.LabelFor(model => model.TEL)</th> <td> @Html.TextBoxFor(model => model.TEL) @Html.ValidationMessageFor(model => model.TEL, "", new { }) </td> </tr> <tr> <th>@Html.LabelFor(model => model.ADDRESS)</th> <td> @Html.TextBoxFor(model => model.ADDRESS) @Html.ValidationMessageFor(model => model.ADDRESS, "", new { }) </td> </tr> <tr> <td><input type="submit"></td> <td></td> </tr> </table> }
執行程式後,網址輸入localhost:xxxx/Home/Create,可以看到下列畫面。 因為@Html.LabelFor() 沒有給予名稱,所以直接呈現binding ViewModel 內的變數名稱。
接著,我們可以在ViewModel 先增加using System.CompinentModel,接著在每一個變數上 設定 DisplayName 屬性,在View 的 @Html.LabelFor 即可以顯示欄位名稱。
我們可以在Controller設定中斷點並執行程式後,於網頁上輸入資料並送出,即可檢視資料 內容,確認是否有做到model binder的效果。
我們能增加 Model 驗證與驗證描述,當使用者違反欄位限制的時候,提示使用者訊息。 下列這些語法能幫助我們:
@Html.AntiForgeryToken() @Html.ValidationSummary(true, "", new { }) @Html.ValidationMessageFor()
我們能在 ViewModel 增加 Reqired Annotations,讓這欄位必須輸入: 我們能在 ViewModel 增加電子郵件驗證,檢查是否符合電子郵件格式: 我們能在 ViewModel 增加正規表達式驗證,讓這個欄位符合條件:
範例
https://dl.dropboxusercontent.com/u/13585157/ViewModelExample.zip感想
回到學校教導學弟妹專題,很開心的直接分享程式內容,直接對 ViewModel進行程式講 解,才發現一堆學弟妹完全不知道我在講什麼。立刻回頭更改教學內容,從基礎的內容 講解起,但也已經難以挽回,效果不彰。運氣很好,還有第二次教學弟妹的機會,將教 材順序做了調整,而這一批的學習成效,比起第一批學弟妹,效果好很多。 教導學生教材與自己學習的內容筆記是完全兩碼子的事情,要寫出簡顯易懂的程式教學 ,是非常困難的事情,而這也是我目前不斷努力改進的地方。本篇文章內容歡迎分享,轉載與使用圖文請來信告知並註明出處。
5 留言
感謝你詳細的教學
回覆刪除不知道為何MVC5中文教學頗少......
希望對你有幫助 :)
刪除你的介紹對初學很有幫助~~感謝您^_^
刪除謝謝您的文章, 我學習Asp.net MVC的過程中, 部份是照著你的文章一步一步練習做的。我這裡有兩點建議想提供:
回覆刪除一、文章裡的View 內容的範例 @using (Html.BeginForm( .... 裡面加入了new { enctype = "multipart/form-data" }, 這應該是不需要的, 據我了解, enctype = "multipart/form-data" 是用在如果表單內有檔案要上傳的時候才需要如此設定
二、範例中的Form裡面有加入 @Html.AntiForgeryToken(), 這是用來防止CSRF攻擊, 但是光只加這一行是無效的, 必須也要在Form對應到的Action、也就是Controller裡的第二個Create方法的上面要加入 [ValidateAntiForgeryToken], 這樣才能讓這個安全性的設定生效
Hi
刪除感謝您閱讀我的文章。您提第一點與第二點完全沒錯。
當初在設計這份教材時,這一章節專注於資料傳遞與 DTO 之間的關係,有些重要的細節不小心沒有注意到,深感抱歉,也感謝您的補充。