Learning Notes of ASP.NET MVC
Tags: learning, aspdotnet, mvc, netcore
Published: 2020-05-29 02:12:36

*(Original reference: https://zh.wikipedia.org/wiki/ASP.NET_MVC_Framework)*
- Initial release on 17 March 2009.
- Latest release (ASP.NET MVC 5.2) on 24 December 2014.
- ASP.NET MVC Framework includes in the package of System.Web.Mvc.
- Core namespaces of ASP.NET
  - System.Web.Mvc
  - HtmlHelper
  - System.Web.Mvc.Html
- ASP.NET MVC support below view of type
  - Normal view (.aspx, supported by ViewPage)
  - Partial view (.ascx, supported by ViewUserControl)
  - Layout view (.master, suppoted by ViewMasterPage)
- Type of View Engine
  - Web Form
  - Razor View
- Support HTTP methods
  - HttpVerbs.Get
  - HttpVerbs.Post
  - HttpVerbs.Delete
  - HttpVerbs.Put
  - HttpVerbs.Head

*(GitHub: https://github.com/aspnet/AspNetWebStack)*

# Controller
Support on method decorator
- HttpVerbs.Get
- HttpVerbs.Post
- HttpVerbs.Delete
- HttpVerbs.Put
- HttpVerbs.Head

Type of ActionResult
- ViewResult物件，這個物件內裝載了IView介面的資訊，以及IViewEngine的資訊，實際產生輸出資料的會是 IViewEngine，以及其指示的 View 物件。
- PartialViewResult物件，與ViewResult相似，但它回傳的是"部份展示"，即使用者控制項的View。
- ContentResult物件，裝載由使用者自訂的 Content-Type 以及資料。
- EmptyResult物件，表示不回傳任何東西。
- HttpUnauthorizedReuslt物件，表示動作沒有被授權（即 HTTP 401）的錯誤訊息。
- JavaScriptResult物件，表示回傳的是JavaScript指令碼。
- JsonResult物件，表示回傳的是JSON資料。
- FileResult物件，表示回傳的是一個檔案資料。
- RedirectResult物件，表示回傳的是一個重導向 (HTTP Redirect) 指令。
- RedirectToRouteResult物件，與 RedirectResult 類似，但是它是重導向給一個 Route 的路徑。

``` cs
using System.Linq;
using System.Web.Mvc;
using System.Web;
using System;

    // GET: /Person/
    public ActionResult Index()
    {
        return View(people);
    }

    // GET: /Person/Details/5
    public ActionResult Details(Person person)
    {
        return View(person);
    }

    // GET: /Person/Create
    public ActionResult Create()
    {
        return View();
    } 

    // POST: /Person/Create
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Person person)
    {
        if (!ModelState.IsValid)
        {
            return View("Create", person);
        }

        people.Add(person);

        return RedirectToAction("Index");
    }
```

# View
ASP.NET supports three types of view
- .aspx網頁，由 ViewPage 來支援。
- .ascx使用者控制項，由 ViewUserControl 來支援。
- .master主版頁面，由 ViewMasterPage 來支援。
``` html
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head runat="server">
    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
</head>

<body>
    <div class="page">

        <div id="header">
            <div id="title">
                <h1>My MVC Application</h1>
            </div>

            <div id="logindisplay">
                <% Html.RenderPartial("LogOnUserControl"); %>
            </div> 

            <div id="menucontainer">

                <ul id="menu">              
                    <li><%= Html.ActionLink("Home", "Index", "Home")%></li>
                    <li><%= Html.ActionLink("About", "About", "Home")%></li>
                </ul>

            </div>
        </div>

        <div id="main">
            <asp:ContentPlaceHolder ID="MainContent" runat="server" />

            <div id="footer">
            </div>
        </div>
    </div>
</body>
</html>
```

# Model Validation
``` cs
/*
 * Manually Validation
 */
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Person person)
{
    if (person.Name.Trim().Length == 0)
    {
        ModelState.AddModelError("Name", "Name is required.");
    }
    if (person.Age < 1 || person.Age > 200)
    {
        ModelState.AddModelError("Age", "Age must be within range 1 to 200.");
    }
    if ((person.Zipcode.Trim().Length > 0) && (!Regex.IsMatch(person.Zipcode, @"^\d{5}$|^\d{5}-\d{4}$")))
    {
        ModelState.AddModelError("Zipcode", "Zipcode is invalid.");
    }
    if (!Regex.IsMatch(person.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
    {
        ModelState.AddModelError("Phone", "Phone number is invalid.");
    }
    if (!Regex.IsMatch(person.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
    {
        ModelState.AddModelError("Email", "Email format is invalid.");
    }
    if (!ModelState.IsValid)
    {
        return View("Create", person);
    }

    people.Add(person);

    return RedirectToAction("Index");
}

/*
 * Use Data Annotation
 */
using System.ComponentModel.DataAnnotations;  
namespace MvcDA {
    [MetadataType(typeof(ProductMD))]
    public partial class Product {
        public class ProductMD {
            [StringLength(50),Required]
            public object Name { get; set; }
            [StringLength(15)]
            public object Color { get; set; }
            [Range(0, 9999)]
            public object Weight { get; set; }
          //  public object NoSuchProperty { get; set; }
        }
    }
}
```
``` html
<h2>Create</h2>

<%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>

<% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="Name">Name:</label>
            <%= Html.TextBox("Name") %> Required
            <%= Html.ValidationMessage("Name", "*") %>
        </p>
        <p>
            <label for="Age">Age:</label>
            <%= Html.TextBox("Age") %> Required
            <%= Html.ValidationMessage("Age", "*") %>
        </p>
        <p>
            <label for="Street">Street:</label>
            <%= Html.TextBox("Street") %>
            <%= Html.ValidationMessage("Street", "*") %>
        </p>
        <p>
            <label for="City">City:</label>
            <%= Html.TextBox("City") %>
            <%= Html.ValidationMessage("City", "*") %>
        </p>
        <p>
            <label for="State">State:</label>
            <%= Html.TextBox("State") %>
            <%= Html.ValidationMessage("State", "*") %>
        </p>
        <p>
            <label for="Zipcode">Zipcode:</label>
            <%= Html.TextBox("Zipcode") %>
            <%= Html.ValidationMessage("Zipcode", "*") %>
        </p>
        <p>
            <label for="Phone">Phone:</label>
            <%= Html.TextBox("Phone") %> Required
            <%= Html.ValidationMessage("Phone", "*") %>
        </p>
        <p>
            <label for="Email">Email:</label>
            <%= Html.TextBox("Email") %> Required
            <%= Html.ValidationMessage("Email", "*") %>
        </p>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>

<% } %>

<div>
    <%=Html.ActionLink("Back to List", "Index") %>
</div>
```

# Html Helper
``` javascript
// Render
Html.Encode | Html.AttributeEncode
Html.ActionLink | Html.RouteLink
Html.Partial | Html.RenderPartial
Html.DisplayFor | Html.DisplayTextFor | Html.DisplayNameFor
Html.FormatValue | Html.Raw

// Verification
Html.EnableClientValidation | Html.EnableUnobtrusiveJavaScript

// Form related
Html.BeginForm | Html.EndForm
Html.AntiForgeryToken
Html.EditorFor | Html.LabelFor | Html.Hidden
Html.Password | Html.RadioButton | Html.CheckBox
Html.TextBox | Html.TextArea | Html.DropDownList
Html.ListBox
Html.ValidationMessageFor | Html.ValidationSummary
```