目录

概述

在模型中添加验证规则

自定义验证规则

伙伴类的使用

总结

系列文章

[Asp.net MVC]Asp.net MVC5系列——第一个项目

[Asp.net MVC]Asp.net MVC5系列——添加视图

[Asp.net MVC]Asp.net MVC5系列——添加模型

[Asp.net MVC]Asp.net MVC5系列——从控制器访问模型中的数据

[Asp.net MVC]Asp.net MVC5系列——添加数据

概述

上篇文章中介绍了添加数据,在提交表单的数据的时候,我们需要对数据的合法性进行校验,Asp.net MVC5中,提供一种方便的验证方式。本文介绍如何在我们的Student模型中添加一些验证规则,同时确认当用户使用我们的应用程序创建或编辑学生信息时将使用这些验证规则对用户输入的信息进行检查。

DRY原则

在ASP.NET MVC中,有一条作为核心的原则,就是DRY(“Don’t Repeat Yourself,中文意思为:不要让开发者重复做同样的事情)原则。ASP.NET MVC提倡让开发者“一处定义、处处可用”。这样可以减少开发者的代码编写量,同时也更加便于代码的维护。

在模型中添加验证规则

首先,让我们在Student类中追加一些验证规则。

打开Student.cs文件,在文件的头部追加一条引用System.ComponentModel.DataAnnotations命名空间的using语句,代码如下所示。

   using System.ComponentModel.DataAnnotations;

这个System.ComponentModel.DataAnnotations命名空间是.NET Framework中的一个命名空间。它提供了很多内建的验证规则,你可以对任何类或属性显式指定这些验证规则。

现在让我们来修改Student类,增加一些内建的Required(必须输入),StringLength(输入字符长度)与Range(输入范围)验证规则,当然,我们也可以自定义我们自己的验证规则,之后会说明如何创建自定义验证规则。

  //------------------------------------------------------------------------------
// <auto-generated>
// 此代码已从模板生成。
//
// 手动更改此文件可能导致应用程序出现意外的行为。
// 如果重新生成代码,将覆盖对此文件的手动更改。
// </auto-generated>
//------------------------------------------------------------------------------ namespace Wolfy.FirstMVCProject.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; public partial class Student
{
public Student()
{
this.Score = new HashSet<Score>();
} public int stuId { get; set; }
[Required(ErrorMessage = "必须输入标题")]
public string stuName { get; set; } public string stuSex { get; set; }
public System.DateTime stuBirthdate { get; set; }
public System.DateTime stuStudydate { get; set; }
[StringLength(, ErrorMessage = "只能输入4个字符")]
public string stuAddress { get; set; }
[Required(ErrorMessage = "必须输入标题")]
//正则验证
[RegularExpression(@"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$", ErrorMessage = "邮箱格式不正确")]
public string stuEmail { get; set; }
[RegularExpression(@"\d{11}", ErrorMessage = "邮箱格式不正确")]
public string stuPhone { get; set; }
public Nullable<bool> stuIsDel { get; set; }
public Nullable<System.DateTime> stuInputtime { get; set; }
public int classId { get; set; } public virtual Course Course { get; set; }
public virtual ICollection<Score> Score { get; set; }
}
}

上述这些验证属性指定了我们想要强加给模型中各属性的验证规则。Required属性表示必须要指定一个属性值,在上例中,一个有效的学生信息必须含有标题,地址,电话,邮箱。Range属性表示属性值必须在一段范围之间。StringLength属性表示一个字符串属性的最大长度或最短长度。

Action中的代码

          [HttpPost]
public ActionResult Create(Student student)
{
//ModelState.IsValid校验客户端数据是否全部符合验证规则
if (ModelState.IsValid)
{
//获取dropdownlist选中的value值
string strClassID = Request.Form["class"];
int intId = Convert.ToInt32(strClassID);
var course = from c in entity.Course
where c.classId == intId
select c;
//处理外键关系
student.Course = course.FirstOrDefault();
entity.Student.Add(student);
entity.SaveChanges();
return RedirectToAction("Index"); }
else
{
//在不符合验证规则的时候,得重新绑定DropDownList数据源。
var courses = from s in entity.Course
select s;
List<SelectListItem> items = new List<SelectListItem>();
foreach (var item in courses)
{
SelectListItem selectListItem = new SelectListItem() { Text = item.className, Value = item.classId.ToString() };
items.Add(selectListItem);
}
ViewData["class"] = items;
return View(student);
}
}

运行效果

自定义验证规则

如果上面的验证规则,不能满足需要,可以自己定义验证规则,首先看一下,Required是如何实现的,咱们就模仿Required来实现一个自己的验证规则。

  namespace System.ComponentModel.DataAnnotations
{
// 摘要:
// 指定需要数据字段值。
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class RequiredAttribute : ValidationAttribute
{
// 摘要:
// 初始化 System.ComponentModel.DataAnnotations.RequiredAttribute 类的新实例。
public RequiredAttribute(); // 摘要:
// 获取或设置一个值,该值指示是否允许空字符串。
//
// 返回结果:
// 如果允许空字符串,则为 true;否则为 false。 默认值为 false。
public bool AllowEmptyStrings { get; set; } // 摘要:
// 检查必填数据字段的值是否不为空。
//
// 参数:
// value:
// 要验证的数据字段值。
//
// 返回结果:
// 如果验证成功,则为 true;否则为 false。
//
// 异常:
// System.ComponentModel.DataAnnotations.ValidationException:
// 数据字段值为 null。
public override bool IsValid(object value);
}
}
   // 摘要:
// 作为所有验证属性的基类。
//
// 异常:
// System.ComponentModel.DataAnnotations.ValidationException:
// 在设置非本地化 System.ComponentModel.DataAnnotations.ValidationAttribute.ErrorMessage
// 属性错误消息的同时,本地化错误消息的 System.ComponentModel.DataAnnotations.ValidationAttribute.ErrorMessageResourceType
// 和 System.ComponentModel.DataAnnotations.ValidationAttribute.ErrorMessageResourceName
// 属性也被设置。
public abstract class ValidationAttribute : Attribute
{
//其他代码
}

所以,验证规则特性必须集成ValidationAttribute类,当然也可以继承该类的子类。(注意:对于特性约定以Attribute结尾)。
我们就自定义一个验证类,实现默认值约束规则DefaultsAttribute,而实现最简单的方式就是自定义正则表达式的规则。

定义的验证类的代码如下:

      public class DefaultsAttribute : RegularExpressionAttribute
{
public DefaultsAttribute()
: base("[mf]")
{ }
public override string FormatErrorMessage(string name)
{
return "性别只能输入m(男)或者f(女)";
}
}

为Student类中的stuSex加上特性。

         [Defaults]
public string stuSex { get; set; }

然后测试一下,看看实现效果

在Create视图(追加学生信息视图)与Create方法内部是如何实现验证的?

该方法中的ModelState.IsValid属性用来判断是否提交的学生信息数据中包含有任何没有通过数据验证的无效数据。如果存在无效数据,Create方法重新返回追加学生信息视图。如果数据全部有效,则将该条数据保存到数据库中。

我们之前创建的使用支架模板的Create.cshtml视图模板中的代码显示如下,在首次打开追加学生信息视图与数据没有通过验证时,Create方法中返回的视图都是使用的这个视图模板。

  1 @model Wolfy.FirstMVCProject.Models.Student
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>Create</title>
13 </head>
14 <body>
15 @using (Html.BeginForm("Create","Student",FormMethod.Post))
16 {
17 @Html.AntiForgeryToken()
18
19 <div class="form-horizontal">
20 <h4>Student</h4>
21 <hr />
22 @Html.ValidationSummary(true)
23
24 <div class="form-group">
25 @Html.LabelFor(model => model.stuName, new { @class = "control-label col-md-2" })
26 <div class="col-md-10">
27 @Html.EditorFor(model => model.stuName)
28 @Html.ValidationMessageFor(model => model.stuName)
29 </div>
30 </div>
31
32 <div class="form-group">
33 @Html.LabelFor(model => model.stuSex, new { @class = "control-label col-md-2" })
34 <div class="col-md-10">
35 @Html.EditorFor(model => model.stuSex)
36 @Html.ValidationMessageFor(model => model.stuSex)
37 </div>
38 </div>
39
40 <div class="form-group">
41 @Html.LabelFor(model => model.stuBirthdate, new { @class = "control-label col-md-2" })
42 <div class="col-md-10">
43 @Html.EditorFor(model => model.stuBirthdate)
44 @Html.ValidationMessageFor(model => model.stuBirthdate)
45 </div>
46 </div>
47
48 <div class="form-group">
49 @Html.LabelFor(model => model.stuStudydate, new { @class = "control-label col-md-2" })
50 <div class="col-md-10">
51 @Html.EditorFor(model => model.stuStudydate)
52 @Html.ValidationMessageFor(model => model.stuStudydate)
53 </div>
54 </div>
55
56 <div class="form-group">
57 @Html.LabelFor(model => model.stuAddress, new { @class = "control-label col-md-2" })
58 <div class="col-md-10">
59 @Html.EditorFor(model => model.stuAddress)
60 @Html.ValidationMessageFor(model => model.stuAddress)
61 </div>
62 </div>
63
64 <div class="form-group">
65 @Html.LabelFor(model => model.stuEmail, new { @class = "control-label col-md-2" })
66 <div class="col-md-10">
67 @Html.EditorFor(model => model.stuEmail)
68 @Html.ValidationMessageFor(model => model.stuEmail)
69 </div>
70 </div>
71
72 <div class="form-group">
73 @Html.LabelFor(model => model.stuPhone, new { @class = "control-label col-md-2" })
74 <div class="col-md-10">
75 @Html.EditorFor(model => model.stuPhone)
76 @Html.ValidationMessageFor(model => model.stuPhone)
77 </div>
78 </div>
79
80 <div class="form-group">
81 @Html.LabelFor(model => model.stuIsDel, new { @class = "control-label col-md-2" })
82 <div class="col-md-10">
83 @Html.EditorFor(model => model.stuIsDel)
84 @Html.ValidationMessageFor(model => model.stuIsDel)
85 </div>
86 </div>
87
88 <div class="form-group">
89 @Html.LabelFor(model => model.stuInputtime, new { @class = "control-label col-md-2" })
90 <div class="col-md-10">
91 @Html.EditorFor(model => model.stuInputtime)
92 @Html.ValidationMessageFor(model => model.stuInputtime)
93 </div>
94 </div>
95
96 <div class="form-group">
97 @Html.LabelFor(model => model.Course.classId, "stuClass", new { @class = "control-label col-md-2" })
98 <div class="col-md-10">
99 @Html.DropDownList("class", String.Empty)
100 @Html.ValidationMessageFor(model => model.classId)
101 </div>
102 </div>
103
104 <div class="form-group">
105 <div class="col-md-offset-2 col-md-10">
106 <input type="submit" value="Create" class="btn btn-default" />
107 </div>
108 </div>
109 </div>
110 }
111
112 <div>
113 @Html.ActionLink("Back to List", "Index")
114 </div>
115 </body>
116 </html>

请注意在这段代码中使用了许多Html.EditorFor帮助器来为Student类的每个属性输出一个输入文本框。在每个Html.EditorFor帮助器之后紧跟着一个Html.ValidationMessageFor帮助器。这两个帮助器将与从控制器传入的模型类的对象实例(在本示例中为Student对象的一个实例)结合起来,自动寻找指定给模型的各个验证属性,然后显示对应的验证错误信息。

这种验证体制的好处是在于控制器和Create视图(追加学生信息视图)事先都即不知道实际指定的验证规则,也不知道将会显示什么验证错误信息。验证规则和错误信息只在Student类中被指定。

如果我们之后想要改变验证规则,我们也只要在一处地方进行改变就可以了。我们不用担心整个应用程序中存在验证规则不统一的问题,所有的验证规则都可以集中在一处地方进行指定,然后在整个应用程序中使用这些验证规则。这将使我们的代码更加清晰明确,更加具有可读性、可维护性与可移植性。这将意味着我们的代码是真正符合DRY原则(一处指定,到处可用)的。

伙伴类

这个demo中,我们使用的是EF的方式操作数据库的,如果数据库中表的字段有变化时,我们就要更新模型,如图所示:

如果从数据库中更新模型,就会把上面添加的规则给替换掉,那么之前写的验证规则就白费了,那么有没有解决办法呢?办法是有的,就是将要说的伙伴类。伙伴类的定义如下,

      public class StudentValidate
{
public int stuId { get; set; }
[Required(ErrorMessage="姓名是必须的")]
public string stuName { get; set; }
public string stuSex { get; set; }
public System.DateTime stuBirthdate { get; set; }
public System.DateTime stuStudydate { get; set; }
public string stuAddress { get; set; }
public string stuEmail { get; set; }
public string stuPhone { get; set; }
public Nullable<bool> stuIsDel { get; set; }
public Nullable<System.DateTime> stuInputtime { get; set; }
public int classId { get; set; }
}
//指定要与数据模型类关联的元数据类。
[MetadataType(typeof(StudentValidate))]
public partial class Student
{ }
}
你创建另外一个类,包含你的验证特性和元数据,然后通过将 “MetadataType”特性施加到一个与工具生成的类一起编译的partial类上,将其与由设计器生成的类连接起来。例如,如果我们想要将我们前面用到的验证规则施加到由LINQ to SQL 或 ADO.NET EF设计器维护的Student类上,我们可以更新我们的验证代码,使其存在于一个单独的“StudentValidate”类上。
测试,如上面代码所示,为了简单测试,我们只验证姓名是必须的字段,其他的验证规则跟上面一样,就不再一一添加了,感兴趣的可以自己测试一下。
这种方式可以避免因为从数据库更新模型而造成之前的model别修改。

总结

本文介绍了表单验证的方式,当然,你也可以使用客户端的校验方式,表单验证插件也挺多的,这里就不再赘述了。另外介绍了自定义的验证规则,在验证方式不符合自己要求的时候,可以自定义一个验证规则,当然你可以直接使用正则表达式的验证规则,但是如果这个验证规则经常使用,那么将它定义为一个规则特性,像使用Required一样去使用,是不是更方便?在文章最后,介绍了一种由于更新model造成原来的model改变,修改了原来的验证规则,可以通过伙伴类来保证原来的验证规则不变,又能更新model。

Asp.net MVC]Asp.net MVC5系列——在模型中添加的更多相关文章

  1. [Asp.net MVC]Asp.net MVC5系列——在模型中添加验证规则

    目录 概述 在模型中添加验证规则 自定义验证规则 伙伴类的使用 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net MVC5 ...

  2. [Asp.net MVC]Asp.net MVC5系列——布局视图

    目录 系列文章 概述 布局视图 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net MVC5系列——添加视图 [Asp.net M ...

  3. Asp.net MVC]Asp.net MVC5系列——Routing特性

    目录 概述 路由特性 使用路由 可选参数和参数的默认值 路由前缀 默认路由 路由约束 自定义路由约束 路由名 区域(Area) 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列— ...

  4. Asp.net MVC]Asp.net MVC5系列——实现编辑、删除与明细信息视图

    目录 概述 实现信息的明细视图 实现信息的编辑视图 实现信息的删除视图 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net ...

  5. [Asp.net MVC]Asp.net MVC5系列——添加视图

    目录 系列文章 概述 添加视图 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 概述 在这一部分我们添加一个新的控制器HelloWorldController类, ...

  6. [Asp.net MVC]Asp.net MVC5系列——添加模型

    目录 概述 添加模型 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net MVC5系列——添加视图 概述 在本节中我们将追加 ...

  7. [Asp.net MVC]Asp.net MVC5系列——从控制器访问模型中的数据

    目录 概述 从控制器访问模型中的数据 强类型模型与@model关键字 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net M ...

  8. [Asp.net MVC]Asp.net MVC5系列——添加数据

    目录 概述 显示添加数据时所用表单 处理HTTP-POST 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net MVC5系列 ...

  9. ASP.NET MVC 5 - 开始MVC5之旅

    本教程将使用Visual Studio 2013手把手教你构建一个入门的ASP.NET MVC5 Web应用程序.本教程配套的C#源码工程可通过如下网址下载:C#版本源码链接.同时,请查阅 Build ...

随机推荐

  1. linux环境中通过useradd命令,创建用户的时候指定用户的base-dir

    需求说明: 今天一个同事,问了一个这样的问题,在linux环境中,创建用户的时候,默认的是在/home目录下创建一个与用户名相同的家目录, 如何能够将这个/home更换成一个其他的,比如/opt/ap ...

  2. MAC软件下载比较好的三个第三方网站

    http://soft.macx.cn; http://www.applex.net: http://www.macdang.com;

  3. OC中Runtime浅析

    近期了解了一下OC的Runtime,真的是OC中非常强大的一个机制,看起来比較底层,但事实上能够有非常多活用的方式. 什么是Runtime 我们尽管是用Objective-C写的代码,事实上在运行过程 ...

  4. Java按钮控件数组实现计算器界面

    编写程序,通过按钮数组来管理界面中的所有按钮控件,从而使用最少的代码实现模拟的计算器界面. 思路如下: 创建一个类,通过extends使其继承窗体类JFrame: 创建一个JFrame对象,使用JFr ...

  5. js数组获取相同元素个数,归档排序

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 【NLP】HanLP环境

    1.参考:https://github.com/hankcs/pyhanlp 2.问题: C:\Users\ADMINI~1\AppData\Local\Temp\pip-install-u617cf ...

  7. 【ArcGIS】WebAdaptorIIS 安装前准备及配置Portal For ArcGIS的问题解决

    1.计算机全名配置 2.IIS-服务器证书配置 3.端口绑定 备注:配置Portal For ArcGIS总会提示计算机域名.全名错误.完全限定域名,可能就是没有进行第一步操作 4.Portal目录

  8. python commands模块在python3.x被subprocess取代

    subprocess 可以执行shell命令的相关模块和函数有: os.systemos.spawnos.popen --废弃popen2.* --废弃commands.* --废弃,3.x中被移除 ...

  9. adb(android debug bridge)命令

    adb(android debug bridge) adb devices --查看当前连接的模拟器/设备 adb remount --模拟器/设备重新启动,保证能用 adb push src des ...

  10. 2014 华为校招机试题(c/c++开发类)

    第一题: 1.2.3....n盏灯,同时有n个人, 第1个人将1的倍数的灯拉一下, 第2个人将2的倍数的灯拉一下, ...... 问最后有几盏灯是亮的, 初始状态下灯是灭的, 输入整数n(n<6 ...