譯文,個人原創(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):

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

@{
  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>

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

圖41.7顯示了瀏覽器中打開的頁面。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

圖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):

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

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");
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

要顯示結(jié)果,可以顯示ViewBag.Info的值(代碼文件MVCSampleApp/Views/SubmitData/Index.cshtml):

@ViewBag.Info

模型綁定器

不僅可以在action方法使用多個參數(shù),還還可以使用包含與傳入字段名稱匹配的屬性的類型(代碼文件 MVCSampleApp/Controllers/SubmitDataController.cs):

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

[HttpPost]
public IActionResult CreateMenu2(Menu m)
{
  ViewBag.Info =
    $"menu created: {m.Text}, Price: {m.Price}, category: {m.Category}";
  return View("Index");
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

用戶使用表單提交數(shù)據(jù)時,將調(diào)用一個 CreateMenu 方法,顯示帶有提交的菜單數(shù)據(jù)的Index視圖,如圖41.8所示。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

圖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:

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

[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");
  }
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

注釋和驗(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):

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

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; }
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

用于驗(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):

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

[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");
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

如果使用工具生成的模型類,您可能認(rèn)為很難向?qū)傩蕴砑犹匦?。由于工具生成的類被定義為部分類,可以通過添加屬性和方法,實(shí)現(xiàn)額外的接口,以及實(shí)現(xiàn)由工具生成的類使用的部分方法來擴(kuò)展類。如果無法更改類型的源代碼,則無法向現(xiàn)有屬性和方法添加特性,但對于這種情況有幫助!假設(shè)Menu類是由工具生成的部分類。然后,不同名稱的新類(例如,MenuMetadata)可以定義與實(shí)體類相同的屬性,并添加注釋,如下所示:

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

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; }
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

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):

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

public IActionResult HelperWithMenu() => View(GetSampleMenu());
private Menu GetSampleMenu() =>
  new Menu
  {
    Id = 1,
    Text ="Schweinsbraten mit Kn&ouml;del und Sauerkraut",
    Price = 6.9,
    Date = new DateTime(2016, 10, 5),
    Category ="Main"
  };

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

視圖的模型定義為 Menu 類型。 HTML Helper 的DisplayName 從參數(shù)返回文本,如上一個示例所示。 Display方法使用一個表達(dá)式作為參數(shù),其中屬性名稱可以以字符串格式傳遞。這種方式下,屬性嘗試查找具有此名稱的屬性,并訪問屬性訪問器以返回屬性的值(代碼文件MVCSampleApp/Views/HTMLHelpers/HelperWithMenu.cshtml):

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

@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")

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

生成的HTML代碼,可以視為調(diào)用DisplayName和Display方法的輸出:

Text:
Schweinsbraten mit Kn&#246;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):

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

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));
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

自定義擴(kuò)展方法 ToSelectListItems 在類SelectListItemsExtensions中定義,它擴(kuò)展了來自cars集合的 IDictionary<intstring> 類型。在實(shí)現(xiàn)中,字典中的每個項(xiàng)目返回一個新的 SelectListItem 對象(代碼文件MVCSampleApp/Extensions/SelectListItemsExtensions.cs):

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

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()
      });
  }
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動開發(fā)培訓(xùn)

在視圖中幫助方法 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