译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(中)),不对的地方欢迎指出与交流。 

章节出自《Professional C# 6 and .NET Core 1.0》。水平有限,各位阅读时仔细分辨,唯望莫误人子弟。

附英文版原文: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(下)

------------------------------------  

从客户端提交数据

直到现在,只使用来自客户端的 HTTP GET 请求从服务器检索HTML代码。从客户端发送表单数据怎么办?

为了提交表单数据,为控制器 SubmitData 创建视图 CreateMenu。该视图包含一个HTML表单元素,用于定义应将哪些数据发送到服务器。 form方法被声明为 HTTP POST 请求。定义输入字段的 input 元素都具有与Menu类型的属性对应的名称(代码文件 MVCSampleApp/Views/SubmitData/CreateMenu.cshtml):

iOS培训,Swift培训,苹果开发培训,移动开发培训

@{
  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培训,Swift培训,苹果开发培训,移动开发培训

图41.7显示了浏览器中打开的页面。

iOS培训,Swift培训,苹果开发培训,移动开发培训

图41.7

在 SubmitData 控制器中,创建两个 CreateMenu 操作方法:一个用于 HTTP GET 请求,另一个用于 HTTP POST 请求。因为C#允许不同的方法有相同的名称,只需要参数号或类型不同。当然,这个要求与操作方法是一致。 Action方法也需要与HTTP请求方法不同。默认请求方法是GET,当你应用属性 HttpPost 时,请求方法是POST。要读取HTTP POST数据,可以从 Request 对象使用信息。但是,定义有参数的 CreateMenu 方法要简单得多。参数与表单字段的名称相匹配(代码文件MVCSampleApp/Controllers/SubmitDataController.cs):

iOS培训,Swift培训,苹果开发培训,移动开发培训

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培训,Swift培训,苹果开发培训,移动开发培训

要显示结果,可以显示ViewBag.Info的值(代码文件MVCSampleApp/Views/SubmitData/Index.cshtml):

@ViewBag.Info

模型绑定器

不仅可以在action方法使用多个参数,还还可以使用包含与传入字段名称匹配的属性的类型(代码文件 MVCSampleApp/Controllers/SubmitDataController.cs):

iOS培训,Swift培训,苹果开发培训,移动开发培训

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

iOS培训,Swift培训,苹果开发培训,移动开发培训

用户使用表单提交数据时,将调用一个 CreateMenu 方法,显示带有提交的菜单数据的Index视图,如图41.8所示。

iOS培训,Swift培训,苹果开发培训,移动开发培训

图41.8

模型绑定器负责从 HTTP POST 请求传输数据。模型绑定器实现接口 IModelBinder。默认情况下 FormCollectionModelBinder 类用于将输入字段绑定到模型。这个binder支持基本类型,模型类(例如 Menu 类型)和实现  ICollection<T> , IList<T> 和  IDictionary<TKey, TValue> 的集合。

如果不是所有参数类型的属性都要填充模型绑定器,则可以使用 Bind 属性。使用此属性,可以指定应包含在绑定中的属性名称列表。

还可以使用没有参数的操作方法将输入数据传递到模型,如下一个代码段所示。创建一个新的Menu类实例,并将此实例传递给 Controller 基类的 TryUpdateModelAsync 方法。如果更新后的模型在更新后不处于有效状态,TryUpdateModelAsync 将返回false:

iOS培训,Swift培训,苹果开发培训,移动开发培训

[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培训,Swift培训,苹果开发培训,移动开发培训

注释和验证

可以向模型类型添加一些注释,这些注释用于更新数据的验证。命名空间 System.ComponentModel.DataAnnotations 包含可用于客户端上指定的信息数据并可用于验证的特性类型。(译者注:为了区分 Attribute 和 property,将 Attribute 译为“特性”,property 译为“属性”,二者虽然含有属性的意思,其实还是有些区别的,感兴趣的读者可以查阅相关资料,此处不作详细介绍。)

这些添加的特性可以在Menu类作更改(代码文件MVCSampleApp/Models/Menu.cs):

iOS培训,Swift培训,苹果开发培训,移动开发培训

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培训,Swift培训,苹果开发培训,移动开发培训

用于验证的常用的特性类型有,CompareAttribute 用于比较不同的属性,CreditCardAttribute用于验证有效的信用卡号,EmailAddressAttribute 用于验证电子邮件地址,EnumDataTypeAttribute用于将输入与枚举值进行比较,PhoneAttribute用于验证电话号码。

还可以使用其他特性来获取显示和错误消息的值,例如 DataTypeAttribute 和 DisplayFormatAttribute。

要使用验证属性,以下所示的操作方法中使用 ModelState.IsValid 可用于验证模型的状态(代码文件MVCSampleApp/Controllers/SubmitDataController.cs):

iOS培训,Swift培训,苹果开发培训,移动开发培训

[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培训,Swift培训,苹果开发培训,移动开发培训

如果使用工具生成的模型类,您可能认为很难向属性添加特性。由于工具生成的类被定义为部分类,可以通过添加属性和方法,实现额外的接口,以及实现由工具生成的类使用的部分方法来扩展类。如果无法更改类型的源代码,则无法向现有属性和方法添加特性,但对于这种情况有帮助!假设Menu类是由工具生成的部分类。然后,不同名称的新类(例如,MenuMetadata)可以定义与实体类相同的属性,并添加注释,如下所示:

iOS培训,Swift培训,苹果开发培训,移动开发培训

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培训,Swift培训,苹果开发培训,移动开发培训

MenuMetadata类必须链接到Menu类。使用工具生成的部分类,可以在同一命名空间中创建另一个部分类型,以将MetadataType特性添加到创建连接的类型定义中:

[MetadataType(typeof(MenuMetadata))]
public partial class Menu
{
}

HTML Helper方法还可以利用注释向客户端添加信息。

使用HTML Helpers

HTML Helpers 是创建HTML代码的助手。在视图中Razor语法可以直接使用它们。

Html 是视图基类 RazorPage 的属性,属于 IHtmlHelper 类型。 HTML Helper 方法被实现为扩展方法来扩展 IHtmlHelper 接口。

类 InputExtensions 定义了 HTML 辅助方法来创建复选框、密码控件、单选按钮和文本框控件。 Action 和 RenderAction 辅助方法由 ChildActionExtensions 类定义。显示的辅助方法由 DisplayExtensions 类定义。 HTML表单的辅助方法由类FormExtensions定义。

以下部分介绍使用HTML Helpers的一些示例。

使用简单助手

以下代码段使用HTML助手方法 BeginForm,Label和CheckBox。 BeginForm启动一个表单元素。还有一个EndForm用于结束表单元素。该示例使用从BeginForm方法返回的MvcForm实现的IDisposable接口(来释放资源)。释放 MvcForm 时,会调用EndForm。这样,BeginForm方法可以被一个using语句包围,以便在关闭的大括号中结束表单。方法 DisplayName 直接返回参数中的内容,方法CheckBox是一个type 特性设置为checkbox的 input 元素(代码文件MVCSampleApp/Views/HelperMethods/SimpleHelper.cshtml):

@using (Html.BeginForm()) {
  @Html.DisplayName("Check this (or not)")
  @Html.CheckBox("check1")
}

下一个代码段显示生成的HTML代码。 CheckBox方法创建两个具有相同名称的输入元素,一个设置为 hidden 。这种行为有一个重要的原因:如果复选框的值为false,浏览器不会将表单内容的此信息传递给服务器。只将所选的复选框的值传递到服务器。此HTML特性会自动绑定动作方法的参数,从而产生问题。一个简单的解决方案是通过CheckBox助手方法执行的。该方法创建相同名称并设置为false的隐藏输入元素。如果未选中该复选框,则隐藏的输入元素将传递到服务器,并且可以绑定false值。如果选中此复选框,则会向服务器发送两个具有相同名称的输入元素。第一个输入元素设置为true;第二个设置为false。使用自动绑定,仅选择第一个输入元素进行绑定:

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

使用模型数据

可以对模型数据使用辅助方法。示例创建一个 Menu 对象。这个类型在本章前面在 Models 目录中已声明,并将一个样例菜单作为模型传递给视图(代码文件MVCSampleApp/Controllers/HTMLHelpersController.cs):

iOS培训,Swift培训,苹果开发培训,移动开发培训

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培训,Swift培训,苹果开发培训,移动开发培训

视图的模型定义为 Menu 类型。 HTML Helper 的DisplayName 从参数返回文本,如上一个示例所示。 Display方法使用一个表达式作为参数,其中属性名称可以以字符串格式传递。这种方式下,属性尝试查找具有此名称的属性,并访问属性访问器以返回属性的值(代码文件MVCSampleApp/Views/HTMLHelpers/HelperWithMenu.cshtml):

iOS培训,Swift培训,苹果开发培训,移动开发培训

@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培训,Swift培训,苹果开发培训,移动开发培训

生成的HTML代码,可以视为调用DisplayName和Display方法的输出:

Text:
Schweinsbraten mit Kn&#246;del und Sauerkraut
<br />Category:
Main

注意 助手方法还提供强类型变量来访问模型的成员。有关详细信息,请参阅“使用强类型助手”部分。

定义HTML属性

大多数HTML Helper方法都有重载,可以传递任何HTML属性。例如,以下TextBox方法创建一个类型为 text 的输入元素。第一个参数定义名称,第二个参数定义使用文本框设置的值。 TextBox方法的第三个参数是对象类型,它允许传递一个匿名类型,其中每个属性都被更改为HTML元素的特性。这里输入元素的结果是required 特性设置为required,maxlength特性设置为15,class特性设置为CSSDemo。因为类是一个C#关键字,它不能直接设置为属性。但是它以@为前缀以生成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" />

创建列表

为了显示列表,存在类似 DropDownList和ListBox的辅助方法。这些方法创建HTML选择元素。

在控制器中,首先创建一个包含键和值的字典。然后,字典将使用自定义扩展方法 ToSelectListItems 转换为 SelectListItem 的列表。 DropDownList 和 ListBox 方法使用 SelectListItem 集合(代码文件MVCSampleApp/Controllers/HTMLHelpersController.cs):

iOS培训,Swift培训,苹果开发培训,移动开发培训

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培训,Swift培训,苹果开发培训,移动开发培训

自定义扩展方法 ToSelectListItems 在类SelectListItemsExtensions中定义,它扩展了来自cars集合的 IDictionary<intstring> 类型。在实现中,字典中的每个项目返回一个新的 SelectListItem 对象(代码文件MVCSampleApp/Extensions/SelectListItemsExtensions.cs):

iOS培训,Swift培训,苹果开发培训,移动开发培训

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培训,Swift培训,苹果开发培训,移动开发培训

在视图中帮助方法 DropDownList 直接访问从控制器返回的模型(代码文件MVCSampleApp/Views/HTMLHelpers/HelperList.cshtml):

@{
    ViewBag.Title ="Helper List";
}
@model IEnumerable<SelectListItem>
<h2>Helper2</h2>@Html.DropDownList("carslist", Model)

生成的HTML创建一个 select 元素,其中包含从 SelectListItem 创建的选项子元素,并定义从控制器返回的所选项:

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

使用强类型助手

HTML Helper方法提供强类型方法来访问从控制器传递的模型。这些方法都以名称For后缀。例如,可以使用TextBoxFor方法代替TextBox方法。

以下示例再次使用控制器返回单个实体(代码文件MVCSampleApp/Controllers/HTMLHelpersController.cs):

public IActionResult StronglyTypedMenu() => View(GetSampleMenu());

视图使用 Menu 类型作为模型,因此方法 DisplayNameFor 和 DisplayFor 可以直接访问 Menu 属性。默认情况下,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) 可以设置模型的Text属性。此方法还使用添加到 Menu 类型的Text属性的注释。 Text属性添加了 Required 和 MaxStringLength 特性,这就是从TextBoxFor方法返回 data-val-lengt

作者:沐汐 Vicky

出处:http://www.cnblogs.com/EasyInvoice

欢迎转载,但未经作者同意必须保留此段声明,否则保留追究法律责任的权利.

http://www.cnblogs.com/EasyInvoice/p/6444143.html

网友评论