目录

概述

在模型中添加验证规则

自定义验证规则

伙伴类的使用

总结

系列文章

[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方法中返回的视图都是使用的这个视图模板。

 @model Wolfy.FirstMVCProject.Models.Student

 @{
Layout = null;
} <!DOCTYPE html> <html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Create</title>
</head>
<body>
@using (Html.BeginForm("Create","Student",FormMethod.Post))
{
@Html.AntiForgeryToken() <div class="form-horizontal">
<h4>Student</h4>
<hr />
@Html.ValidationSummary(true) <div class="form-group">
@Html.LabelFor(model => model.stuName, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.stuName)
@Html.ValidationMessageFor(model => model.stuName)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.stuSex, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.stuSex)
@Html.ValidationMessageFor(model => model.stuSex)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.stuBirthdate, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.stuBirthdate)
@Html.ValidationMessageFor(model => model.stuBirthdate)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.stuStudydate, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.stuStudydate)
@Html.ValidationMessageFor(model => model.stuStudydate)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.stuAddress, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.stuAddress)
@Html.ValidationMessageFor(model => model.stuAddress)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.stuEmail, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.stuEmail)
@Html.ValidationMessageFor(model => model.stuEmail)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.stuPhone, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.stuPhone)
@Html.ValidationMessageFor(model => model.stuPhone)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.stuIsDel, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.stuIsDel)
@Html.ValidationMessageFor(model => model.stuIsDel)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.stuInputtime, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.stuInputtime)
@Html.ValidationMessageFor(model => model.stuInputtime)
</div>
</div> <div class="form-group">
@Html.LabelFor(model => model.Course.classId, "stuClass", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("class", String.Empty)
@Html.ValidationMessageFor(model => model.classId)
</div>
</div> <div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
} <div>
@Html.ActionLink("Back to List", "Index")
</div>
</body>
</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/Core表单提交后台模型二级属性验证问题

    起因 这个是网友在官网论坛的提问:https://fineui.com/bbs/forum.php?mod=viewthread&tid=22237 重新问题 本着务实求真的态度,我们先来复现 ...

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

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

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

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

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

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

  6. ASP.NET MVC4 新手入门教程之八 ---8.向模式中添加验证

    在这本部分会将验证逻辑添加到Movie模式,和你会确保验证规则执行任何时候用户试图创建或编辑使用该应用程序的一部电影. 保持事物的干练性 ASP.NET MVC 的核心设计信条之一是 DRY(”Don ...

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

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

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

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

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

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

随机推荐

  1. Hibernate入门案例及增删改查

    一.Hibernate入门案例剖析: ①创建实体类Student 并重写toString方法 public class Student { private Integer sid; private I ...

  2. Smokeping -- 监控网络质量

    1.下载fping.echoping.smokeping 链接:http://pan.baidu.com/s/1pL4HLYb 密码:fxe2 2.安装依赖包 yum install -y perl ...

  3. Dialog详解(包括进度条、PopupWindow、自定义view、自定义样式的对话框)

    Dialog详解(包括进度条.PopupWindow.自定义view.自定义样式的对话框)   Android中提供了多种对话框,在实际应用中我们可能会需要修改这些已有的对话框.本实例就是从实际出发, ...

  4. 当Python在appium中使用if……else语句不好使怎么办

    前几天写自动化脚本的时候,有个地方需要用if--else判断获得的ID和name是哪个,从而决定点击哪个按钮,我用if--else去判断,可是总是提示我找不到对应的元素, 在网上爬了好久,最终终于找到 ...

  5. js阿拉伯数字转中文大写

    function DX(n) { if (!/^(0|[1-9]\d*)(\.\d+)?$/.test(n)) return "数据非法"; var unit = "千百 ...

  6. Java 8新特性终极指南

    目录结构 介绍 Java语言的新特性 2.1 Lambdas表达式与Functional接口 2.2 接口的默认与静态方法 2.3 方法引用 2.4 重复注解 2.5 更好的类型推测机制 2.6 扩展 ...

  7. SQL联合查询(内联、左联、右联、全联)的语法(转)

    最近在做一个比较复杂的业务,涉及的表较多,于是在网上找了一些sql联合查询的例子进行研究使用. 概述: 联合查询效率较高,举例子来说明联合查询:内联inner join .左联left outer j ...

  8. .Net Core Linux centos7行—hyper-v安装linux系统和.net core sdk

    下载linux系统,选择安装centos7 下载地址:https://www.centos.org/download/ 安装centos7 hyper-v选择新建虚拟机 根据向导一路next,虚拟机代 ...

  9. gdb调试常用实用命令和core dump文件的生成

      1.生成core dump文件的方法: $  ulimit -c //查看是否为0 如果为0 $   ulimit -c unlimited 这样在程序崩溃以后会在当前目录生成一个core.xxx ...

  10. 【Ural】1519. Formula 1

    http://acm.timus.ru/problem.aspx?space=1&num=1519 题意:给一个n×m的棋盘,其中'.'是空白,'*'是障碍,求经过所有点的哈密顿回路的数目.( ...