目录

概述

在模型中添加验证规则

自定义验证规则

伙伴类的使用

总结

系列文章

[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. 查询SQL阻塞语句

    SELECT SPID=p.spid, DBName = convert(CHAR(),d.name), ProgramName = program_name, LoginName = convert ...

  2. Go 语言机制之逃逸分析

    https://blog.csdn.net/weixin_38975685/article/details/79788254   Go 语言机制之逃逸分析 https://blog.csdn.net/ ...

  3. python2和3的区别,怎么样做到轻松切换2和3

    以下是菜鸟教程列举的.这些零散的改变需要注意. 下面这些东西可能平时的程序根本没用到,或者稍加注意就可以了.但2和3最主要的区别是,掌握编码. 编码在所有程序中无处不在,处理不好,要么乱码,要么编码解 ...

  4. 下拉刷新 上拉更多 支持ListView GridView WebView【转载】

    转载自:http://www.stay4it.com/?p=245 老贴重发,源代码放附件了,需要的下载把. 终于有新货了.昨天改了下,在ListView和GridView加了个返回到顶部的按钮,li ...

  5. Spring IOC-ContextLoaderListener

    [spring version : 4.1.6.RELEASE] 使用spring的项目中,一般都会在web.xml中配置ContextLoaderListener,它就是spring ioc 的入口 ...

  6. 手机APP支付--整合支付宝支付控件

    长话短说,本文根据支付宝官方说明文档,简单总结下,并且说明下开发过程碰到的问题以及该如何解决. 整合步骤: 1 登录商家服务网站,下载开发包,地址:https://b.alipay.com/order ...

  7. 利用powershell进行windows日志分析

    0x00 前言 Windows 中提供了 2 个分析事件日志的 PowerShell cmdlet:一个是Get-WinEvent,超级强大,但使用起来比较麻烦:另一个是Get-EventLog,使得 ...

  8. Perl操作Oracle

    一. perl连接Oracle数据库 [oracle@oracle11gR2 perl_script]$ more connect.pl #!/usr/bin/perl #perl script us ...

  9. Github上star数超1000的Android列表控件

    Android开发中,列表估计是最最常使用到的控件之一了.列表相关的交互如下拉刷新,上拉更多,滑动菜单,拖动排序,滑动菜单,sticky header分组,FAB等等都是十分常见的体验.Github中 ...

  10. [转]logging使用

    来源:https://www.cnblogs.com/nancyzhu/p/8551506.html日志 日志是跟踪软件运行时所发生的事件的一种方法.软件开发者在代码中调用日志函数,表明发生了特定的事 ...