添加验证——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语句块来包含邮件的发送代码,当邮件发送不成功的时候可以用来警告用户。


<---本节完--->


ASP.NET MVC4 学习笔记-4的更多相关文章

  1. asp.net mvc4 学习笔记一(基本原理)

    做了8年的asp.net webform,用过MVVM但还没用过MVC , 虽然项目不用MVC,但是还是想了解一下,今天第二天学习,以下是学习心得. VS2012默认带有asp.net mvc3和as ...

  2. ASP.NET MVC4学习笔记路由系统概念与应用篇

    一.概念 1.路由是计算机网络中的一个技术概念,表示把数据包从一个网段转发至另一网段.ASP.NET中的路由系统作用类似,其作用是把请求Url映射到相应的"资源"上,资源可以是一段 ...

  3. ASP.NET MVC4学习笔记之总体概述

    断断续续使用ASP.NET MVC框架也有一年多了,也算积累了一些经验,唉,一直想写一些笔记好好总结一下,人太懒不想动笔,今天终于决定开始.希望自己能坚持下去. 这篇文章大体介绍ASP.NET MVC ...

  4. ASP.NET MVC4学习笔记之Controller的激活

    一. 高层相关类说明 当路由系统根据请求Url收集路由信息后,下一步就要将路由信息传给Controller激活系统,Controller激活系统负责实现了IController接口的Controlle ...

  5. ASP.NET MVC4学习笔记路由系统实现

    一.路由实现 路由系统实际是一个实现了ASP.NET IHttpModule接口的模块,通过注册HttpApplication的PostResolveRequestCache 事件对Url路由处理.总 ...

  6. ASP.NET MVC4学习笔记

    一.MVC简介

  7. ASP.NET MVC4学习笔记之Controller激活的扩展

    一. 为什么要进行扩展 在前面的分析中,我们知道默认的Controller激活系统只能实例化无参构造函数的Controller类型,但在某些情况一下,我们希望某些服务的实例能够自动注入到Control ...

  8. ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则

    ASP.NET MVC 学习笔记-7.自定义配置信息   ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...

  9. [ASP.NET MVC] ASP.NET Identity学习笔记 - 原始码下载、ID型别差异

    [ASP.NET MVC] ASP.NET Identity学习笔记 - 原始码下载.ID型别差异 原始码下载 ASP.NET Identity是微软所贡献的开源项目,用来提供ASP.NET的验证.授 ...

  10. ASP.NET MVC学习笔记-----Filter2

    ASP.NET MVC学习笔记-----Filter(2) 接上篇ASP.NET MVC学习笔记-----Filter(1) Action Filter Action Filter可以基于任何目的使用 ...

随机推荐

  1. sql计算众数及中位数

    众数 众数: 情况①:一组数据中,出现次数最多的数就叫这组数据的众数. 举例:1,2,3,3,4的众数是3. 情况② :如果有两个或两个以上个数出现次数都是最多的,那么这几个数都是这组数据的众数. 举 ...

  2. .Net Core工作流WorkFlowCore

    前言 WorkFlowCore是一个针对.NetCore的轻量级的工作流引擎,提供了FluentAPI.多任务.持久化以及并行处理的功能,适合于小型工作流.责任链的需求开发.支持工作流长期运行,提供了 ...

  3. Kubernetes入门实践(Job/CronJob)

    基于Pod的设计理念,Kubernetes有两种对象Job和CronJob Job和CronJob组合了Pod,实现了对离线业务的处理.如Nginx和busybox,分别代表了Kubernetes里的 ...

  4. Springboot整合Flowable6.x导出bpmn20

    项目源码仓库 BPMN2.0(Business Process Model and Notation)是一套业务流程模型与符号建模标准,以XML为载体,以符号可视化业务,支持精准的执行语义来描述元素的 ...

  5. 区块链——Lab2

    区块链的典型数据结构 比特币:UTXO模型,以交易后找零为中心 ETH:Account 模型,以账户余额为中心(就是账户的形式) 区块链交易 用户发起交易 矿工验证交易(能够得到 区块奖励) 验证成功 ...

  6. Spring配置数据库连接

    <beans xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="ht ...

  7. [双目视差] 立体校正源码分析(opencv)

    文章目录 [双目视差] 立体校正源码分析(opencv) 一.源码解析 二.源码中的方法 [双目视差] 立体校正源码分析(opencv) 一.源码解析 立体校正:把实际中非共面行对准的两幅图像,校正成 ...

  8. ABC267G Increasing K Times 题解

    做这道题,很有感悟,发篇文. 先给数列从小到大排个序. 接下来设 \(f_{i,j}\) 表示前 \(i\) 个数的排列形成 \(j\) 个上坡的方案数. 接下来考虑转移,分为插入第 \(i\) 个数 ...

  9. #PowerBi 1分钟学会,以“万”为单位显示数据

    PowerBi是一款强大的数据分析和可视化工具,它可以帮助我们快速地制作出各种图表和报表,展示数据的价值和洞察. 但是,有时候我们的数据量太大,导致图表上的数字难以阅读和比较.例如,如果我们想要查看某 ...

  10. 2020-01-26:mysql8.0做了什么改进?

    福哥答案2020-01-26: [2020-01-26:mysql8.0做了什么改进?](http://bbs.xiangxueketang.cn/question/1244)帐户管理增加了对角色的支 ...