譯文,個人原創(chuàng),轉(zhuǎn)載請注明出處(C# 6 與 .NET Core 1.0 高級編程 - 41 ASP.NET MVC(中)),不對的地方歡迎指出與交流。
章節(jié)出自《Professional C# 6 and .NET Core 1.0》。水平有限,各位閱讀時仔細(xì)分辨,唯望莫誤人子弟。
附英文版原文:Professional C# 6 and .NET Core 1.0 - Chapter 41 ASP.NET MVC
C# 6 與 .NET Core 1.0 高級編程 - 41 ASP.NET MVC(上)
C# 6 與 .NET Core 1.0 高級編程 - 41 ASP.NET MVC(下)
------------------------------------
從客戶端提交數(shù)據(jù)
直到現(xiàn)在,只使用來自客戶端的 HTTP GET 請求從服務(wù)器檢索HTML代碼。從客戶端發(fā)送表單數(shù)據(jù)怎么辦?
為了提交表單數(shù)據(jù),為控制器 SubmitData 創(chuàng)建視圖 CreateMenu。該視圖包含一個HTML表單元素,用于定義應(yīng)將哪些數(shù)據(jù)發(fā)送到服務(wù)器。 form方法被聲明為 HTTP POST 請求。定義輸入字段的 input 元素都具有與Menu類型的屬性對應(yīng)的名稱(代碼文件 MVCSampleApp/Views/SubmitData/CreateMenu.cshtml):
@{ ViewBag.Title ="Create Menu"; } <h2>Create Menu</h2> <form action="/SubmitData/CreateMenu" method="post"> <fieldset> <legend>Menu</legend> <div>Id:</div> <input name="id" /> <div>Text:</div> <input name="text" /> <div>Price:</div> <input name="price" /> <div>Category:</div> <input name="category" /> <div></div> <button type="submit">Submit</button> </fieldset> </form>
圖41.7顯示了瀏覽器中打開的頁面。
圖41.7
在 SubmitData 控制器中,創(chuàng)建兩個 CreateMenu 操作方法:一個用于 HTTP GET 請求,另一個用于 HTTP POST 請求。因?yàn)镃#允許不同的方法有相同的名稱,只需要參數(shù)號或類型不同。當(dāng)然,這個要求與操作方法是一致。 Action方法也需要與HTTP請求方法不同。默認(rèn)請求方法是GET,當(dāng)你應(yīng)用屬性 HttpPost 時,請求方法是POST。要讀取HTTP POST數(shù)據(jù),可以從 Request 對象使用信息。但是,定義有參數(shù)的 CreateMenu 方法要簡單得多。參數(shù)與表單字段的名稱相匹配(代碼文件MVCSampleApp/Controllers/SubmitDataController.cs):
public IActionResult Index() => View(); public IActionResult CreateMenu() => View(); [HttpPost] public IActionResult CreateMenu(int id, string text, double price, string category) { var m = new Menu { Id = id, Text = text, Price = price }; ViewBag.Info = $"menu created: {m.Text}, Price: {m.Price}, category: {m.Category}"; return View("Index"); }
要顯示結(jié)果,可以顯示ViewBag.Info的值(代碼文件MVCSampleApp/Views/SubmitData/Index.cshtml):
@ViewBag.Info
模型綁定器
不僅可以在action方法使用多個參數(shù),還還可以使用包含與傳入字段名稱匹配的屬性的類型(代碼文件 MVCSampleApp/Controllers/SubmitDataController.cs):
[HttpPost] public IActionResult CreateMenu2(Menu m) { ViewBag.Info = $"menu created: {m.Text}, Price: {m.Price}, category: {m.Category}"; return View("Index"); }
用戶使用表單提交數(shù)據(jù)時,將調(diào)用一個 CreateMenu 方法,顯示帶有提交的菜單數(shù)據(jù)的Index視圖,如圖41.8所示。
圖41.8
模型綁定器負(fù)責(zé)從 HTTP POST 請求傳輸數(shù)據(jù)。模型綁定器實(shí)現(xiàn)接口 IModelBinder。默認(rèn)情況下 FormCollectionModelBinder 類用于將輸入字段綁定到模型。這個binder支持基本類型,模型類(例如 Menu 類型)和實(shí)現(xiàn) ICollection<T> , IList<T> 和 IDictionary<TKey, TValue> 的集合。
如果不是所有參數(shù)類型的屬性都要填充模型綁定器,則可以使用 Bind 屬性。使用此屬性,可以指定應(yīng)包含在綁定中的屬性名稱列表。
還可以使用沒有參數(shù)的操作方法將輸入數(shù)據(jù)傳遞到模型,如下一個代碼段所示。創(chuàng)建一個新的Menu類實(shí)例,并將此實(shí)例傳遞給 Controller 基類的 TryUpdateModelAsync 方法。如果更新后的模型在更新后不處于有效狀態(tài),TryUpdateModelAsync 將返回false:
[HttpPost] public async Task<IActionResult> CreateMenu3Result() { var m = new Menu(); bool updated = await TryUpdateModelAsync<Menu>(m); if (updated) { ViewBag.Info = $"menu created: {m.Text}, Price: {m.Price}, category: {m.Category}"; return View("Index"); } else { return View("Error"); } }
注釋和驗(yàn)證
可以向模型類型添加一些注釋,這些注釋用于更新數(shù)據(jù)的驗(yàn)證。命名空間 System.ComponentModel.DataAnnotations 包含可用于客戶端上指定的信息數(shù)據(jù)并可用于驗(yàn)證的特性類型。(譯者注:為了區(qū)分 Attribute 和 property,將 Attribute 譯為“特性”,property 譯為“屬性”,二者雖然含有屬性的意思,其實(shí)還是有些區(qū)別的,感興趣的讀者可以查閱相關(guān)資料,此處不作詳細(xì)介紹。)
這些添加的特性可以在Menu類作更改(代碼文件MVCSampleApp/Models/Menu.cs):
public class Menu { public int Id { get; set; } [Required, StringLength(50)] public string Text { get; set; } [Display(Name="Price"), DisplayFormat(DataFormatString="{0:C}")] public double Price { get; set; } [DataType(DataType.Date)] public DateTime Date { get; set; } [StringLength(10)] public string Category { get; set; } }
用于驗(yàn)證的常用的特性類型有,CompareAttribute 用于比較不同的屬性,CreditCardAttribute用于驗(yàn)證有效的信用卡號,EmailAddressAttribute 用于驗(yàn)證電子郵件地址,EnumDataTypeAttribute用于將輸入與枚舉值進(jìn)行比較,PhoneAttribute用于驗(yàn)證電話號碼。
還可以使用其他特性來獲取顯示和錯誤消息的值,例如 DataTypeAttribute 和 DisplayFormatAttribute。
要使用驗(yàn)證屬性,以下所示的操作方法中使用 ModelState.IsValid 可用于驗(yàn)證模型的狀態(tài)(代碼文件MVCSampleApp/Controllers/SubmitDataController.cs):
[HttpPost] public IActionResult CreateMenu4(Menu m) { if (ModelState.IsValid) { ViewBag.Info = $"menu created: {m.Text}, Price: {m.Price}, category: {m.Category}"; } else { ViewBag.Info ="not valid"; } return View("Index"); }
如果使用工具生成的模型類,您可能認(rèn)為很難向?qū)傩蕴砑犹匦?。由于工具生成的類被定義為部分類,可以通過添加屬性和方法,實(shí)現(xiàn)額外的接口,以及實(shí)現(xiàn)由工具生成的類使用的部分方法來擴(kuò)展類。如果無法更改類型的源代碼,則無法向現(xiàn)有屬性和方法添加特性,但對于這種情況有幫助!假設(shè)Menu類是由工具生成的部分類。然后,不同名稱的新類(例如,MenuMetadata)可以定義與實(shí)體類相同的屬性,并添加注釋,如下所示:
public class MenuMetadata { public int Id { get; set; } [Required, StringLength(25)] public string Text { get; set; } [Display(Name="Price"), DisplayFormat(DataFormatString="{0:C}")] public double Price { get; set; } [DataType(DataType.Date)] public DateTime Date { get; set; } [StringLength(10)] public string Category { get; set; } }
MenuMetadata類必須鏈接到Menu類。使用工具生成的部分類,可以在同一命名空間中創(chuàng)建另一個部分類型,以將MetadataType特性添加到創(chuàng)建連接的類型定義中:
[MetadataType(typeof(MenuMetadata))] public partial class Menu { }
HTML Helper方法還可以利用注釋向客戶端添加信息。
使用HTML Helpers
HTML Helpers 是創(chuàng)建HTML代碼的助手。在視圖中Razor語法可以直接使用它們。
Html 是視圖基類 RazorPage 的屬性,屬于 IHtmlHelper 類型。 HTML Helper 方法被實(shí)現(xiàn)為擴(kuò)展方法來擴(kuò)展 IHtmlHelper 接口。
類 InputExtensions 定義了 HTML 輔助方法來創(chuàng)建復(fù)選框、密碼控件、單選按鈕和文本框控件。 Action 和 RenderAction 輔助方法由 ChildActionExtensions 類定義。顯示的輔助方法由 DisplayExtensions 類定義。 HTML表單的輔助方法由類FormExtensions定義。
以下部分介紹使用HTML Helpers的一些示例。
使用簡單助手
以下代碼段使用HTML助手方法 BeginForm,Label和CheckBox。 BeginForm啟動一個表單元素。還有一個EndForm用于結(jié)束表單元素。該示例使用從BeginForm方法返回的MvcForm實(shí)現(xiàn)的IDisposable接口(來釋放資源)。釋放 MvcForm 時,會調(diào)用EndForm。這樣,BeginForm方法可以被一個using語句包圍,以便在關(guān)閉的大括號中結(jié)束表單。方法 DisplayName 直接返回參數(shù)中的內(nèi)容,方法CheckBox是一個type 特性設(shè)置為checkbox的 input 元素(代碼文件MVCSampleApp/Views/HelperMethods/SimpleHelper.cshtml):
@using (Html.BeginForm()) { @Html.DisplayName("Check this (or not)") @Html.CheckBox("check1") }
下一個代碼段顯示生成的HTML代碼。 CheckBox方法創(chuàng)建兩個具有相同名稱的輸入元素,一個設(shè)置為 hidden 。這種行為有一個重要的原因:如果復(fù)選框的值為false,瀏覽器不會將表單內(nèi)容的此信息傳遞給服務(wù)器。只將所選的復(fù)選框的值傳遞到服務(wù)器。此HTML特性會自動綁定動作方法的參數(shù),從而產(chǎn)生問題。一個簡單的解決方案是通過CheckBox助手方法執(zhí)行的。該方法創(chuàng)建相同名稱并設(shè)置為false的隱藏輸入元素。如果未選中該復(fù)選框,則隱藏的輸入元素將傳遞到服務(wù)器,并且可以綁定false值。如果選中此復(fù)選框,則會向服務(wù)器發(fā)送兩個具有相同名稱的輸入元素。第一個輸入元素設(shè)置為true;第二個設(shè)置為false。使用自動綁定,僅選擇第一個輸入元素進(jìn)行綁定:
<form action="/HelperMethods/SimpleHelper" method="post"> Check this (or not) <input id="FileName_check1" name="check1" type="checkbox" value="true" /> <input name="check1" type="hidden" value="false" /> </form>
使用模型數(shù)據(jù)
可以對模型數(shù)據(jù)使用輔助方法。示例創(chuàng)建一個 Menu 對象。這個類型在本章前面在 Models 目錄中已聲明,并將一個樣例菜單作為模型傳遞給視圖(代碼文件MVCSampleApp/Controllers/HTMLHelpersController.cs):
public IActionResult HelperWithMenu() => View(GetSampleMenu()); private Menu GetSampleMenu() => new Menu { Id = 1, Text ="Schweinsbraten mit Knödel und Sauerkraut", Price = 6.9, Date = new DateTime(2016, 10, 5), Category ="Main" };
視圖的模型定義為 Menu 類型。 HTML Helper 的DisplayName 從參數(shù)返回文本,如上一個示例所示。 Display方法使用一個表達(dá)式作為參數(shù),其中屬性名稱可以以字符串格式傳遞。這種方式下,屬性嘗試查找具有此名稱的屬性,并訪問屬性訪問器以返回屬性的值(代碼文件MVCSampleApp/Views/HTMLHelpers/HelperWithMenu.cshtml):
@model MVCSampleApp.Models.Menu @{ ViewBag.Title ="HelperWithMenu"; } <h2>Helper with Menu</h2>@Html.DisplayName("Text:") @Html.Display("Text") <br />@Html.DisplayName("Category:") @Html.Display("Category")
生成的HTML代碼,可以視為調(diào)用DisplayName和Display方法的輸出:
Text: Schweinsbraten mit Knödel und Sauerkraut <br />Category: Main
注意 助手方法還提供強(qiáng)類型變量來訪問模型的成員。有關(guān)詳細(xì)信息,請參閱“使用強(qiáng)類型助手”部分。
定義HTML屬性
大多數(shù)HTML Helper方法都有重載,可以傳遞任何HTML屬性。例如,以下TextBox方法創(chuàng)建一個類型為 text 的輸入元素。第一個參數(shù)定義名稱,第二個參數(shù)定義使用文本框設(shè)置的值。 TextBox方法的第三個參數(shù)是對象類型,它允許傳遞一個匿名類型,其中每個屬性都被更改為HTML元素的特性。這里輸入元素的結(jié)果是required 特性設(shè)置為required,maxlength特性設(shè)置為15,class特性設(shè)置為CSSDemo。因?yàn)轭愂且粋€C#關(guān)鍵字,它不能直接設(shè)置為屬性。但是它以@為前綴以生成CSS樣式的類屬性:
@Html.TextBox("text1","input text here", new { required="required", maxlength=15, @class="CSSDemo" });
生成的HTML輸出如下所示:
<input class="Test" id="FileName_text1" maxlength="15" name="text1" required="required" type="text" value="input text here" />
創(chuàng)建列表
為了顯示列表,存在類似 DropDownList和ListBox的輔助方法。這些方法創(chuàng)建HTML選擇元素。
在控制器中,首先創(chuàng)建一個包含鍵和值的字典。然后,字典將使用自定義擴(kuò)展方法 ToSelectListItems 轉(zhuǎn)換為 SelectListItem 的列表。 DropDownList 和 ListBox 方法使用 SelectListItem 集合(代碼文件MVCSampleApp/Controllers/HTMLHelpersController.cs):
public IActionResult HelperList() { var cars = new Dictionary<int, string>(); cars.Add(1,"Red Bull Racing"); cars.Add(2,"McLaren"); cars.Add(3,"Mercedes"); cars.Add(4,"Ferrari"); return View(cars.ToSelectListItems(4)); }
自定義擴(kuò)展方法 ToSelectListItems 在類SelectListItemsExtensions中定義,它擴(kuò)展了來自cars集合的 IDictionary<int, string> 類型。在實(shí)現(xiàn)中,字典中的每個項(xiàng)目返回一個新的 SelectListItem 對象(代碼文件MVCSampleApp/Extensions/SelectListItemsExtensions.cs):
public static class SelectListItemsExtensions { public static IEnumerable<SelectListItem> ToSelectListItems( this IDictionary<int, string> dict, int selectedId) { return dict.Select(item => new SelectListItem { Selected = item.Key == selectedId, Text = item.Value, Value = item.Key.ToString() }); } }
在視圖中幫助方法 DropDownList 直接訪問從控制器返回的模型(代碼文件MVCSampleApp/Views/HTMLHelpers/HelperList.cshtml):
@{ ViewBag.Title ="Helper List"; } @model IEnumerable<SelectListItem> <h2>Helper2</h2>@Html.DropDownList("carslist", Model)
生成的HTML創(chuàng)建一個 select 元素,其中包含從 SelectListItem 創(chuàng)建的選項(xiàng)子元素,并定義從控制器返回的所選項(xiàng):
<select id="FileName_carslist" name="carslist"> <option value="1">Red Bull Racing</option> <option value="2">McLaren</option> <option value="3">Mercedes</option> <option selected="selected" value="4">Ferrari</option> </select>
使用強(qiáng)類型助手
HTML Helper方法提供強(qiáng)類型方法來訪問從控制器傳遞的模型。這些方法都以名稱For后綴。例如,可以使用TextBoxFor方法代替TextBox方法。
以下示例再次使用控制器返回單個實(shí)體(代碼文件MVCSampleApp/Controllers/HTMLHelpersController.cs):
public IActionResult StronglyTypedMenu() => View(GetSampleMenu());
視圖使用 Menu 類型作為模型,因此方法 DisplayNameFor 和 DisplayFor 可以直接訪問 Menu 屬性。默認(rèn)情況下,DisplayNameFor返回屬性的名稱(在這個例子中,它是Text屬性),DisplayFor 返回屬性的值(代碼文件 MVCSampleApp/Views/HTMLHelpers/StronglyTypedMenu.cshtml):
@model MVCSampleApp.Models.Menu @Html.DisplayNameFor(m => m.Text) <br />@Html.DisplayFor(m => m.Text)
同樣,可以使用返回一個輸入元素的 Html.TextBoxFor(m => m.Text) 可以設(shè)置模型的Text屬性。此方法還使用添加到 Menu 類型的Text屬性的注釋。 Text屬性添加了 Required 和 MaxStringLength 特性,這就是從TextBoxFor方法返回 data-val-lengt
作者:沐汐 Vicky
出處:http://www.cnblogs.com/EasyInvoice
歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,否則保留追究法律責(zé)任的權(quán)利.
http://www.cnblogs.com/EasyInvoice/p/6444143.html