Loading [MathJax]/jax/output/HTML-CSS/jax.js

Wednesday, August 21, 2019

ASP.NET 中的 Form

可能有些 old-school,現在我們都 post json format 到 server,但 project 裏有遇見過 form data 處理速度比 json 快的事例 (我還懵懂的在奇怪為甚麼 project 裏的 post request 在 network 的 xhr section 裏甚麼也看不到,多按幾次才發現按 "all" 就找到了,原來變成了 form data 在傳輸 ...),本着熟習 .net 的心態來學一下 form。

首先我們為一個 form 的頁面 (一個 view) 定義以下 ViewModel:
1
2
3
4
5
6
7
8
9
10
11
using ReallyTrue.Models;
using System.Collections.Generic;
 
namespace ReallyTrue.ViewModel
{
    public class NewCustomerViewModel
    {
        public Customer Customer { get; set; }
        public IEnumerable<Membershiptype> MembershipTypes { get; set; } 
    }
}
其中 Customer 跟 MembershipType 為
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace ReallyTrue.Models
{
    public class Customer
    {
        public int Id { get; set; }
        [Required]
        [StringLength(255)]
        public string Name { get; set; }
        public bool IsSubscribedToNewsletter { get; set; }
        public DateTime? Birthday { get; set; }
        public MembershipType MembershipType { get; set; }
        public int? MembershipTypeId { get; set; }
    }
}
1
2
3
4
5
6
7
8
9
10
11
namespace ReallyTrue.Models
{
    public class MembershipType
    {
        public int Id { get; set; }
        public short SignUpFee { get; set; }
        public string Name { get; set; }
        public byte DurationInMonths { get; set; }
        public byte DiscountRate { get; set; }
    }
}
在 Home controller 我們定義 New method 為
1
2
3
4
5
6
7
8
9
public ActionResult New()
{
    var membershipTypes = _context.MembershipTypes.ToList();
    var viewModel = new NewCustomerViewModel()
    {
        MembershipTypes = membershipTypes
    };
    return View(viewModel);
}
利用這個 viewModel (它會被儲存到 ViewResult.ViewData.Model),我們可以建立 ./home/create的 view (cshtml)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@model ReallyTrue.ViewModel.NewCustomerViewModel
 
@{
    ViewBag.Title = "New Customer";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
<h2>New Customer</h2>
 
@using (Html.BeginForm("Create", "Home"))
{
    <div class="form-group">
        @Html.LabelFor(m => m.Customer.Name)
        @Html.TextBoxFor(m => m.Customer.Name, new { @class = "form-control" })
    </div>
    <div class="form-group">
        <label>Date of Birth</label>
        @Html.TextBoxFor(m => m.Customer.Birthday, new { @class = "form-control" })
    </div>
    <div class="checkbox">
        <label>
            @Html.CheckBoxFor(m => m.Customer.IsSubscribedToNewsletter) Subscribed to Newsletter?
        </label>
    </div>
 
 
    <div class="form-group">
        <label>Membership Type</label>
        @Html.DropDownListFor(m => m.Customer.MembershipTypeId, new SelectList(Model.MembershipTypes, "Id", "Name"), "Select", new { @class = "form-control" })
    </div>
    <button type="submit" class="btn btn-primary">Save</button>
}
它會被編譯成這個様子:

其中 save 按下時,它會把 form data 以 post method 方式傳送到 /home/create 這個 route。因此,我們定義 home controller 中的 create method 為 (attribute 為 HttpPost)
1
2
3
4
5
[HttpPost]
 public ActionResult Create(Customer customer)
 {
     return new EmptyResult();
 }
好,重點來了,form data 的 request 有甚麼,我們收到的東西又會是甚麼?我們利用 debugger 來看看:


一些小實驗,我們同樣可以用 NewCustomerViewModel 來定義 Create method 的 parameter,在 debugger 裏可以看到相似的結果,當然有一些差異,紀錄下來研究內裏的 data binding 怎様運作:


我們可以注意到,id 根本沒有 pass 進去,因此基於 int 不是 nullable 的特性,我們會得到 0 這個結果。

還有一些 form 的 key concept 要學,因為暫時沒有機會應用到所以也不詳細做紀錄了。
  1. Client side: @Html.ValidationMessageFor(m => m,Customer.Name),及 render jquery 的 validation bundle。

    Server side 的簡易 validation:
    在 Create method 中寫上
    1
    2
    3
    4
    5
    6
    7
    8
    if (!ModelState.IsValid)
    {
        //do something, say return View(New ViewModel
        //{ Customer = customer,
        //  MembershipTypes = _context.MembershipTypes.ToList()
        //}
        //)
    }
  2. Data Annotation: [Required], [StringLength(int)], [Range(1,2019)], [Phone], [EmailAddress], [Url], [RegularExpression("...")], ...
  3. Anti-forgery Token  用來防止 malicious attack。

No comments:

Post a Comment