[Asp .Net MVC] ViewModel (Attribute and model binding)

前言

為了這一篇,前面需要鋪了許多的梗,寫了許多可能不是很重要但很基礎的觀念,包含

  1. Html 基礎 (請參考 網頁系統 與 Html基礎簡介)
  2. Controller, Action 與 View 的關係(請參考 Controller and View 1-3)。
  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,對於第一次建立的同學,我們建議兩個方法:

  1. 資料長怎樣,就怎麼設計。
  2. View 需要什麼資料,就怎麼設計。

以學生資料為例,我們需要下列資料:

  1. 學號
  2. 姓名
  3. 班級
  4. 通訊地址
  5. 電子郵件
  6. 連絡電話

首先,先右鍵選取 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進行程式講 解,才發現一堆學弟妹完全不知道我在講什麼。立刻回頭更改教學內容,從基礎的內容 講解起,但也已經難以挽回,效果不彰。運氣很好,還有第二次教學弟妹的機會,將教 材順序做了調整,而這一批的學習成效,比起第一批學弟妹,效果好很多。 教導學生教材與自己學習的內容筆記是完全兩碼子的事情,要寫出簡顯易懂的程式教學 ,是非常困難的事情,而這也是我目前不斷努力改進的地方。

 



本篇文章內容歡迎分享,轉載與使用圖文請來信告知並註明出處。