ASP.NET MVC - 模型验证
ASP.NET MVC - 模型验证(Model verification)
模型验证原理浅析
模型验证用到了模型绑定器、模型验证器(System.Web.Mvc.DataAnnotationsModelValidator)、模型状态(System.Web.Mvc.ModelState)。为模型应用验证特性(一些特性类型)可以使模型具有同时在服务端和客户端验证数据合法性的功能。
当一个请求到达Action后,Action所接收的模型参数会被实例化。实例化时会调用模型验证器。模型验证器会验证提交的数据是否可以成功转化为Action方法所接收的参数类型,如果不能转化,则模型绑定会失败。如果提交的数据能够成功转化为Action所接收的参数类型,那么模型绑定器就会创建参数的实例,接着会进入应用在模型上的验证特性,由验证特性类对模型的数据进行进一步验证,如果验证特性类对数据的验证是失败的,那么错误信息会被自动写入到ModelState字典中。
现在假设用户发起一个请求,提交一个空的查询字符,而Action接收一个DateTime类型的参数,由于用户提交的是空值,而DateTime是不能为空的struct类型,所以模型验证器会验证失败,异常会抛出到客户端。如果这个数据是有效的,那么模型绑定器就会创建参数类型的实例,并将提交的数据绑定到实例上。
再假如用户提交一个表单,Action方法接收一个Order自定义类型,Order具有x和y属性。同样的,模型验证器会验证数据的有效性,如果验证通过,则由模型绑定器创建参数类型的实例,假如Order模型上应用了验证特性类,那么验证特性类就会对模型进行进一步验证,如果Order的x和y验证未通过,则会自动将x和y作为key,将错误信息作为value写入到ModelSate[x].Errors和ModelSate[y].Errors中,同时还会将错误的数据写入ModelSate[x]和ModelSate[y]中。如果视图页面使用了Html.ValidationMessage或Html.ValidationMessageFor,那这两个方法也会将它们的name参数当做key去ModelState中获取key所对应的错误信息,于是,错误信息显示在了视图上,如图:
客户端验证需要的文件
启用客户端验证(包括失焦时触发验证、配合Remote特性的Ajax验证)这需要引入:
<script src="/Scripts/jquery-1.10.2.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
验证特性的本地化
只需要为每个验证特性的构造函数指定一个ErrorMessage的参数即可,如果需要多国语言的本地化验证提示信息,可参考:如何:为 ASP.NET 网页全球化设置区域性和 UI 区域性
各种验证特性
System.ComponentModel.DataAnnotations命名空间下的验证特性 [Required]
//指出此属性是必填的;
[MinLength]
//指出字符的最小长度;
[StringLength]
//指出字符的最大长度,可在构造函数中指定最小长度;
[RegularExpression]
//指出需要匹配的正则式;
[Range]
//指出数字类型的属性的最小值和最大值;
[Compare]
//指出此属性的值与参数指定的属性的值必须完全一样,比如用于验证两次输入的密码;
[HiddenInput]
//指出这个属性是一个隐藏域;
[ScaffoldColumn]
//指出客户端视图通过EditorForModel、DisplayForModel渲染出的Html的某些属性会被隐藏;
[ReadOnly]
//指出服务端开始模型绑定时,不要把应用了此特性的属性更新为客户端提交的新值;
[UIHint]
//指出一个模板名称,视图使用EditorFor、DispalyFor等模板辅助方法时,将应用此模板渲染Html,如果找不到指定的模板,ASP.NET MVC框架会自动使用默认模板进行替换,自定义模板参看:暂略;
[DisplayFormat]
//指出格式化客户端输入框中的值;
[DataType]
//指出输入框的输入模式;
//示例:
[DataType(DataType.Password)]
public string Password { get; set; }
CreditCard
//表示信用卡卡号
Currency
//表示货币值
Custom
//表示自定义数据类型
Date
//表示的日期值
DateTime
//表示为日期和当天的时间
Duration
//表示存在的对象的持续时间
EmailAddress
//表示电子邮件地址
Html
//表示某一HTML文件
ImageUrl
//表示的图像的URL
MultilineText
//表示多行文本
Password
//表示密码值
PhoneNumber
//表示电话号码值
PostalCode
//表示邮政编码
Text
//表示显示文本
Time
//表示一个时间值
Upload
//表示文件上载的数据类型
Url
//表示一个URL值
DataType枚举可能的值如下
System.ComponentModel命名空间下的验证特性 [DisplayName]
//指出此属性在视图的表单中显示的别名;
//示例:
[DisplayName("地址")]
public string Address { get; set; }
System.Web.Mvc命名空间下的验证特性 [Remote]
//指出客户端失焦时将路由到参数指定的控制器的Action中
//由Action做出处理,如果Action返回true则验证通过,否则验证失败
//如果失败,客户端会显示错误信息
//此特性专门用于客户端发起远程请求的Ajax验证
//客户端必须引入相应的Jquery文件
//注意,此特性只用于客户端Ajax的失焦验证,而并未执行正常流程的服务端验证
//所以如果需要服务端验证,则应在服务端应重写一个验证逻辑,因为假如js被禁用,
//此时如果点击提交,那么数据就不会经过Remoe指定的Action验证
//示例:
@{
public class Order
{
public int OrderId { get; set; }
[Remote("CheckUserName", "Account", ErrorMessage = "用户名已经存在")]
public string UserName { get; set; }
} public class AccountController : Controller
{
public JsonResult CheckUserName(string userName)
{
List<string>
userNameList = new List<string>
{
"sam","leo"
};
var result = !userNameList.Contains(userName);//数据库是否没有包含提交的用户名
return Json(result, JsonRequestBehavior.AllowGet);
}
}
} <div class="form-group">
@Html.LabelFor(model => model.UserName)
@Html.EditorFor(model => model.UserName)
@Html.ValidationMessageFor(model => model.UserName, "")
</div>
自定义验证
自定义验证特性
推荐使用这种方式,因为可以结合客户端验证,而后面两种方式比较难用,权当了解。
using System.Web.Mvc;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations; namespace MusicStore.Models
{
public class Order
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
[Remote("CheckUserName", "Account", ErrorMessage = "用户名已经存在")]
public string UserName { get; set; }
[Contains("中国", ErrorMessage = "字符中未包含中国二字")]
[DisplayName("地址")]
public string Address { get; set; }
} //验证提交的数据是否包含中国二字,从ValidationAttribute派生即可自定义验证特性,实现IClientValidatable即可注册客户端验证
public class ContainsAttribute : ValidationAttribute, IClientValidatable
{
public string ContainsStr { get; set; } public ContainsAttribute(string containsStr) : base($"字符中未包含{containsStr}")
{
ContainsStr = containsStr;
}
//为服务端验证编写逻辑
protected override ValidationResult IsValid(object value, ValidationContext context)
{
return value == null ? ValidationResult.Success : value.ToString().Contains(ContainsStr) == false ? new ValidationResult($"字符中未包含{ContainsStr}") : ValidationResult.Success;
}
//为客户端验证进行注册
//Contains特性验证可能应用在模型的多个属性或多个模型的属性上,所以此处以迭代器的方式返回多次调用
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
//使用ModelClientValidationRule对象创建验证逻辑
//ValidationType:指定客户端验证的函数的名称是什么,函数名称必须是小写
//ErrorMessage:指定格式化的错误提示信息
ModelClientValidationRule validationRule = new ModelClientValidationRule { ValidationType = "contains", ErrorMessage = FormatErrorMessage(metadata.DisplayName) };
//客户端验证函数接收的参数,存储在params参数中,客户端通过params.containsvalue,参数名称必须是小写
validationRule.ValidationParameters.Add("containsvalue", ContainsStr);
yield return validationRule;
}
}
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript">
$(document).ready(function () { jQuery.validator.addMethod("contains",
//测试输入的值是否包含服务端的特性验证指定的字符
//inputValue:表单字段失焦后传递的输入的值
//element:表单字段元素
//params:通过服务端GetClientValidationRules方法生成的验证规则返回的验证特性参数的值
function (inputValue, element, params) {
var ContainsValue = params.containsvalue;
return inputValue.length == ? true : inputValue.indexOf(ContainsValue) == - ? false : true;
}
); jQuery.validator.unobtrusive.adapters.add("contains", ["containsvalue"], function (options) {
options.rules["contains"] = {
containsvalue: options.params.containsvalue
};
options.messages["contains"] = options.message;
}); });
</script>
<div class="form-group">
@Html.LabelFor(model => model.Address)
@Html.EditorFor(model => model.Address)
@Html.ValidationMessageFor(model => model.Address, "")
</div>
自定义自验证模型
自验证就是在模型中自定义一个验证逻辑,这比定义一个验证特性更简单,但在模型中定义的验证逻辑只适用于当前模型,不像验证特性可以应用在其它模型上,并且这种方式只能在服务端验证,无法实现客户端验证。
using System.Web.Mvc;
namespace MusicStore.Models
{
public class Order:IValidatableObject
{
public int OrderId { get; set; }
public string City { get; set; }
public string Email { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
Order order = validationContext.ObjectInstance as Order;
System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex("^\\s*([A-Za-z0-9_-]+(\\.\\w+)*@(\\w+\\.)+\\w{2,5})\\s*$");
if (order == null)
{
yield break;
}
else if (!order.City.Contains("重庆"))
{
yield return new ValidationResult("城市中未包含重庆二字", new string[] { "City" });
}
else if (!r.IsMatch(order.Email))
{
yield return new ValidationResult("电邮格式错误", new string[] { "Email" });
}
//……
}
}
}
自定义参数验证
可以在控制器中编写一个验证方法,当Action接收到一个模型时,调用验证方法执行验证,如果验证失败则将错误信息写入ModelState中,此方法没有客户端验证。
public ActionResult Create(Order order)
{
Validate(order);
if (ModelState.IsValid)
{
//……
}
return View(order);
}
//自定义参数验证
private void Validate(Order order)
{
System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex("^\\s*([A-Za-z0-9_-]+(\\.\\w+)*@(\\w+\\.)+\\w{2,5})\\s*$");
if (!(order.City.Contains("重庆")))
{
ModelState.AddModelError("City", "城市中未包含重庆二字");
}
if (!(r.IsMatch(order.Email)))
{
ModelState.AddModelError("Email", "电邮格式错误");
}
}
ASP.NET MVC - 模型验证的更多相关文章
- asp.net mvc 模型验证组件——FluentValidation
asp.net mvc 模型验证组件——FluentValidation 示例 using FluentValidation; public class CustomerValidator: Abst ...
- Asp.Net MVC 模型验证详解-实现客户端、服务端双重验证
概要 在asp.net webform开发中经常会对用户提交输入的信息进行校验,一般为了安全起见大家都会在客户端进行Javascript(利于交互).服务端双重校验(安全).书写校验代码是一个繁琐的过 ...
- ASP.NET没有魔法——ASP.NET MVC 模型验证
在前面的文章中介绍了用户的注册及登录功能,在注册用户时可以通过代码的形式限制用户名及密码的格式,如果不符合要求那么就无法完成操作,如下图: 该功能的原理是Identity基于的Entity Frame ...
- asp.net mvc 模型验证注解,表单提交
一.添加模型 public class Account { public int ID { get; set; } [Display(Name = "姓名")] //设置要显示的字 ...
- asp.net mvc 模型验证-最舒服的验证方式
在院子里发现 http://www.cnblogs.com/yangecnu/p/3759784.html 模型验证方法 1. 一般方法 繁琐, 无数的if else, 在炎炎夏天,我见过一个验证方法 ...
- 当ASP.NET MVC模型验证遇上CKEditor
项目需要,使用到了CKEditor编辑器.这是个很不错的富文本编辑器,但是当它绑定的字段需要进行模型验证的时候,却会出现验证失效的问题.因此本文旨在记录这个问题和给出解决办法.以下以Validatio ...
- ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(下篇)
上一篇<ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)>文章介绍了ASP.NET MVC模型绑定的相关组件和概念,本章将介绍Controller在执行时是如何通过这 ...
- ASP.NET MVC Model验证(四)
ASP.NET MVC Model验证(四) 前言 本篇主要讲解ModelValidatorProvider 和ModelValidator两种类型的自定义实现,前者是Model验证提供程序,而Mod ...
- ASP.NET MVC Model验证(二)
ASP.NET MVC Model验证(二) 前言 上篇内容演示了一个简单的Model验证示例,然后在文中提及到Model验证在MVC框架中默认所处的位置在哪?本篇就是来解决这个问题的,并且会描述一下 ...
随机推荐
- Contest1592 - 2018-2019赛季多校联合新生训练赛第二场(部分题解)
Contest1592 - 2018-2019赛季多校联合新生训练赛第二场 D 10248 修建高楼(模拟优化) H 10252 组装玩具(贪心+二分) D 传送门 题干 题目描述 C 市有一条东西走 ...
- jmeter-录制, 编辑脚本,性能测试全过程review
录制脚本 jmeter下载安装略过不谈,上步骤: 1.在测试计划新建-threads-线程组 2.在工作台新建-非测试原件-http代理服务器,设置端口和包含网址 不包含网址 3.在手机/浏览器,设置 ...
- Luogu P2519 [HAOI2011]problem a
题目链接 \(Click\) \(Here\) \(DP\)神题.以后要多学习一个,练一练智商. 关键点在于把"有\(a_i\)个人分数比我高,\(b_i\)个人分数比我低"这句话 ...
- 1.1实战项目:电影周周看V1(初识小程序)
第一小程序的实战项目: 覆盖的小程序技术: 讲解方式: 学习方法:
- SVN提交前准备
操作步骤1: 操作步骤2: 操作步骤3: 操作步骤4: 操作步骤5: 操作步骤6:查看 操作步骤7:ignore 操作步骤8:直接提交项目
- bzoj2957 奥妙重重的线段树
https://www.lydsy.com/JudgeOnline/problem.php?id=2957 线段树的query和update竟然还可以结合起来用! 题意:小A的楼房外有一大片施工工地, ...
- jmeter counter函数问题
${__counter(FALSE,)}此函数比较奇怪,放在jsr223前置处理器中引用时不知道为啥,第一个值是2.但是放在其他位置时第一个值是1 真是诡异啊!不知道是不是bug呢 放在标题里引用,t ...
- 《Apache kafka实战》读书笔记-kafka集群监控工具
<Apache kafka实战>读书笔记-kafka集群监控工具 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 如官网所述,Kafka使用基于yammer metric ...
- 【JAVA】使用IntelliJ IDEA创建Java控制台工程
1.File->New->Project 2.选择Java,下一步 3.模板有两个:Command Line App和Java Hello World,没有太大区别 4.命名: 5.结果:
- Junit4学习与使用【转】
参考: http://blog.csdn.net/qqhjqs/article/details/42219037