ASP.NET MVC4 学习笔记-4
添加验证——Adding Validation
现在我们要为程序增加数据验证。如果不增加数据验证的话,我们的用户可能会输入错误的数据或者提交一个空白的表格。
在MVC应用程序中,数据验证通常要在域模型中添加,而不是在用户界面中添加。也就是说,只要我们在模型中添加一次数据验证,在程序的任何地方,只要使用了添加验证的模型类都会进行数据验证。ASP.NET支持与属性定义声明,需要添加System.ComponentModel.DataAnnotations命名空间。对GuestResponse添加数据验证后的代码如下所示:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 6 using System.ComponentModel.DataAnnotations; 7 8 namespace PartyInvites.Models { 9 public class GuestResponse { 10 11 [Required(ErrorMessage = "请输入姓名")] 12 public string Name { get; set; } 13 14 [Required(ErrorMessage = "请输入邮箱!")] 15 [RegularExpression(".+\\@.+\\..+",ErrorMessage = "邮箱格式不正确!")] 16 public string Email { get; set; } 17 18 [Required(ErrorMessage = "请输入联系方式!")] 19 public string Phone { get; set; } 20 21 [Required(ErrorMessage = "请选择你是否希望参加!")] 22 public bool? WillAttend { get; set; } 23 } 24 }
添加的数据验证进行了加粗显示。MVC框架可以在模型绑定过程中自动检测并进行数据验证。需要注意的是,我们已经添加了包含数据验证命名空间的引用,因此不用进行全部的拼写就行。
提示:之前我们进行过提示,我们使用了一个可以为空值的WillAttend属性,就是为了做数据验证的时候使用。如果我们使用了一个不能为空的bool类型,我们通过模型绑定得到的值只是true或者false两种,并且我们不能确定用户已经对这个属性进行了选择。一个可以为空值的bool类型可以有三种值:true、false和null。当用户没有进行选择的时候我们假定为空值,如果用户没有进行选择那么在数据验证时将会产生验证错误。
在控制器类中我们可以只用Model.IsVallidate属性来检测是否通过了数据验证。修改RsvpForm方法POST函数如下所示:
1 ... 2 [HttpPost] 3 public ViewResult RsvpForm(GuestResponse guestResponse) { 4 if (ModelState.IsValid) { 5 //TODO:向Party的组织者发送邮件 6 return View("Thanks", guestResponse); 7 } 8 else { 9 //数据验证出现错误 10 return View(); 11 } 12 } 13 ...
如果数据验证正确,MVC将同之前的运行结果一样跳转到Thanks页面。如果数据验证时输入数据错误,将会通过调用没有参数的View()方法重新渲染RsvpFom页面。
仅仅重新显示页面还是不够的,我们要告诉用户出现错误的地方以及我们为什么不能接受用户所提交的数据。我们可以在RsvpForm页面通过使用Html.ValidationSummary()帮助方法来实现这一功能。修改后的代码如下所示:
1 @model PartyInvites.Models.GuestResponse 2 3 @{ 4 Layout = null; 5 } 6 7 <!DOCTYPE html> 8 9 <html> 10 <head> 11 <meta name="viewport" content="width=device-width" /> 12 <title>RsvpForm</title> 13 </head> 14 <body> 15 @using (Html.BeginForm()) { 16 @Html.ValidationSummary() 17 <p>Your name: @Html.TextBoxFor(x => x.Name)</p> 18 <p>Your email: @Html.TextBoxFor(x => x.Email)</p> 19 <p>Your phone: @Html.TextBoxFor(x => x.Phone)</p> 20 <p> 21 Will you attend? 22 @Html.DropDownListFor(x => x.WillAttend,new[]{ 23 new SelectListItem() {Text = "Yes,I'll be there", Value = bool.TrueString}, 24 new SelectListItem() {Text = "No,I can;t come",Value = bool.FalseString} 25 },"Choose an option") 26 </p> 27 <input type="submit" value="Submit RSVP" /> 28 } 29 </body> 30 </html>
如果没有出现数据验证错误,Html.ValidationSummary()方法就会产生类似于占位符的一个隐藏列表项。如果数据验证出现错误,MVC将会是隐藏的列表进行显示并将验证出错的属性信息加载到列表中。运行结果如图所示:
用户将不会被展示Thanks页面,直到用户输入的数据符合GuestResponse所增加的数据验证要求。值得注意的是,当我们输入的数据验证出错时,之前输入的数据将会和验证信息同时出现在新渲染的页面中。这就是我们使用模型绑定的另一个好处。
备注:如果之前开发过ASP.NET Web Forms程序,也许听说过“服务器控制(server control)”的概念,它可以保留一系列的值在一个范围内叫做_VIEWSTATE。ASP.NET MVC的模型绑定和Web Forms中的服务器控制(server control)、回传(postbacks)、页面状态(View State)等概念没有关系。
高亮显示验证信息显示区域——Highlighting Invalid Fields
HTML的帮助方法创建文本输入框、下拉列表等元素可以很方便的进行数据验证信息显示的扩展。使用这种方法可以使用户之前输入的数据验证出现错误的文本输入框继续拧高亮的显示。
当模型类中的属性数据验证发生错误时,HTML的帮助方法将生成一个与HTML轻微不同的代码。例如,下面的代码就是当没有数据验证错误时Html.TextBoxFor(x => x.Name)方法生成的:
<input data-val="true" data-val-required="请输入姓名!" id="Name" name="Name" type="text" value="" />
下面的代码是发生数据验证错误时生成的代码:
<input class="inout-validation-error" data-val="true" data-val-required="请输入用户名!" id="Name" name="Name" type="text" value="" />
数据验证出现错误时生成的代码中增加了一个名为input-validation-error的类。我们可以为这个类创建一个包含CSS样式的样式表,并且其他不同的HTML帮助方法也可以使用。
MVC项目中的另外一个规则就是静态的内容(例如CSS样式表)应该放在名为Content的文件夹下面。在“解决方案资源管理器”中右键单击项目名新建名为“Content”的文件夹,右键单击该文件夹,在弹出菜单中选择“添加”/“新建项”,在弹出“新建项”窗口中选择“样式表(Style Sheet)”、命名为“Site.css”修改Content文件夹下的Site.css文件如下所示:
1 .field-validation-error { 2 color: #f00; 3 } 4 5 .field-validation-valid { 6 display:none; 7 } 8 9 .input-validation-error { 10 border: 1px solid #f00; 11 background-color: #fee; 12 } 13 14 .validation-summary-errors { 15 font-weight: bold; 16 color: #f00; 17 } 18 19 .validation-summary-valid { 20 display: none; 21 }
为了使用这个样式表,我们需要在RsvpForm页面代码中的head部分添加一个引用,如下所示。你所增加的link元素将会作为一个静态的HTML文件。
1 @model PartyInvites.Models.GuestResponse 2 3 @{ 4 Layout = null; 5 } 6 7 <!DOCTYPE html> 8 9 <html> 10 <head> 11 <meta name="viewport" content="width=device-width" /> 12 <link rel="stylesheet" type="text/css" href="~/Content/Site.css" /> 13 <title>RsvpForm</title> 14 </head> 15 <body> 16 @using (Html.BeginForm()) { 17 @Html.ValidationSummary() 18 <p>Your name: @Html.TextBoxFor(x => x.Name)</p> 19 <p>Your email: @Html.TextBoxFor(x => x.Email)</p> 20 <p>Your phone: @Html.TextBoxFor(x => x.Phone)</p> 21 <p> 22 Will you attend? 23 @Html.DropDownListFor(x => x.WillAttend,new[]{ 24 new SelectListItem() {Text = "Yes,I'll be there", Value = bool.TrueString}, 25 new SelectListItem() {Text = "No,I can;t come",Value = bool.FalseString} 26 },"Choose an option") 27 </p> 28 <input type="submit" value="Submit RSVP" /> 29 } 30 </body> 31 </html>
现在,我们可以看到当用户提交的数据发生验证错误后的提示明显的不同,运行结果如下图所示:
完成示例——Completing the Example
这个示例最后需要做的就是要实现向Party的组织者邮件发送部分。要直线这个功能需要添加一个方法来利用.NET framework框架下的e-mail类来创建和发送电子邮件。我们使用的是WebMail方法来实现邮件的创建与发送。WebMail并不在MVC框架里面,但是它可以让我们很方便的实现邮件的发送功能。
备注:我们使用WebMail方法是因为它可以大大减轻我们的工作。通常我们将其封装在一个方法中。
我们希望在渲染Thanks页面的时候来完成邮件的发送,修改Thanks页面代码如下所示:
1 @model PartyInvites.Models.GuestResponse 2 3 @{ 4 Layout = null; 5 } 6 7 <!DOCTYPE html> 8 9 <html> 10 <head> 11 <meta name="viewport" content="width=device-width" /> 12 <title>Thanks</title> 13 </head> 14 <body> 15 @{ 16 try{ 17 WebMail.SmtpServer = "smtp.esample.com"; 18 WebMail.SmtpPort = 587; 19 WebMail.EnableSsl = true; 20 WebMail.UserName = "mySmtpUsername"; 21 WebMail.Password = "mySmtpPassword"; 22 WebMail.From = "rsvps@example.com"; 23 24 WebMail.Send("party-host@example.com", "RSVP Notification", 25 Model.Name + " is " + ((Model.WillAttend ?? false) ? "" : "not") 26 + "attending"); 27 } 28 catch(Exception){ 29 @:<b>Sorry - we coudn't send the email to confirm your RSVP.</b> 30 } 31 } 32 <div> 33 <h1>Thank you, @Model.Name!</h1> 34 @if (Model.WillAttend == true) { 35 @:It's great that you're coming.The drinks are already in the fridge! 36 } 37 else{ 38 @:Sorry to hear that you can't make it,but thanks for letting us know. 39 } 40 </div> 41 </body> 42 </html>
我们增加了一个使用WebMail帮助方法来设置我们e-mail服务器详细信息的Razor短语,包括服务器名字,是否需要SSL连接以及用户的详细信息。当我们设置完所有的详细信息,我们就可以使用WebMail.Send方法来发送邮件。
我们使用try...catch语句块来包含邮件的发送代码,当邮件发送不成功的时候可以用来警告用户。
<---本节完--->