MVC3 自带数据验证

===========一、基础=============
对于web开发人员来说,对用户输入的信息进行验证是一个重要但是繁琐的工作,而且很多开发者都会忽略。asp.net mvc3框架使用的是叫做“数据注解”( DataAnnotations)的方式进行数据验证。
    这种方式允许程序在客户端和服务器端进行双重验证(asp.net的数据验证控件也是双重验证的)。双重验证的好处是 客户端验证会直接相应用户,不用提交表单,也就减轻了服务器的压力还提高了用户体验;而服务器端验证是确保数据的有效性和完整性,因为有时候客户端会关闭脚本功能。
     注意:要实现客户端验证,需要引用jquery以及jquery验证文件:
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Conten("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
    要实现服务器端验证,需要在提交表单后执行ModelState.IsValid
 
 
一、基础验证
1、Require(非空验证)
Model:
    [Required]
        [Display(Name = "用户名")]
        public string UserName { get; set; }
验证结果:

2、StringLength(字符串长度验证)
        可以验证model属性的最大长度和最小长度,分别对应 MaximumLengthMinimumLength,其中MinimumLength是可选的。
Model:
        [Required]
        [StringLength(100, MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "密码")]
        public string Password { get; set; }
验证结果

3、RegularExpression(正则表达式)
    验证符合该正则表达式的属性。
Model:
        [Required]
        [DataType(DataType.EmailAddress)]
        [RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9._]+\.[A-Za-z]{2,4}")]
        [Display(Name = "电子邮件地址")]
        public string Email { get; set; }
验证结果:

 
4、Range(数值范围验证)
        用来指定数值的最大值和最小值,第一个参数是最小值,第二个参数是最大值(包含他们本身)。可以用户int类型以及Double类型。
Model:
        [Required]
        [Range(13, 18)]
        [Display(Name="年龄")]
        public int Age { get; set; }
验证结果:

 
 
二、附加验证
        附加验证是System.Web.Mvc中额外添加的两个验证特性,所以使用时必须添加using System.Web.Mvc
1、Remote(远程验证)
        虽然asp.net mvc3提供了很多在model中直接验证数据的特性,但是很多逻辑复杂的验证没办法在model中来验证,所以mvc3框架提供了这个远程验证特性,他允许开发者在Controller中用C#代码来验证数据的有效性。
        一个很经典的应用时验证用户名是否重复。这个数据验证没办法在客户端验证,除非将所有的用户名都发往客户端(显然这是不可能的)。所以Remote特性只进行服务器端验证。但是它是通过异步的方式进行验证,所以有更好的用户体验。
 
Model:
        [Required]
        [Display(Name = "用户名")]
        [Remote("CheckUserName","Account")]
        public string UserName { get; set; }
Controller:
        public JsonResult CheckUserName(string userName)
        {
            var result = userName == "admin";
            return Json(result, JsonRequestBehavior.AllowGet);
        }
验证结果:
        注意:如果要Post提交,则需要加上HttpMethod=“POST”:
    [Required(ErrorMessageResourceType=typeof(ErrorMessage),ErrorMessageResourceName="UserRequire")]
        [Display(Name = "用户名")]
        [Remote("CheckUserName","Account", HttpMethod="POST")]
        public string UserName { get; set; }

  而Controller中也可以直接接受Post的请求,当然你加上[Httppost]也是可以的:

        //[HttpPost]
        public JsonResult CheckUserName(string userName)
        {
            var result = userName != "admin";
            return Json(result, JsonRequestBehavior.AllowGet);
        }
 
2、Compare(相同验证)
        Compare特性是用来验证输入的两个数据是否完全相同。最典型的例子就是注册时两次输入的密码是否相同。
Model:
复制代码
        [Required]
        [StringLength(100, ErrorMessage = "{0} 必须至少包含 {2} 个字符。", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "密码")]
        public string Password { get; set; }
 
 
        [DataType(DataType.Password)]
        [Display(Name = "确认密码")]
        [Compare("Password", ErrorMessage = "密码和确认密码不匹配。")]
        public string ConfirmPassword { get; set; }
复制代码
验证结果:

MVC3 自带数据验证_第1张图片

 
 
        上面的是asp.net mvc3框架的几种常用的数据注解,除了后两种mvc特有的特性,其他的特性都在System.ComponentModel.DataAnnotations中,恰当的使用会大大提高开发效率。具体的参见: http://msdn.microsoft.com/zh-cn/library/system.componentmodel.dataannotations.aspx

===========二、错误信息的自定义及其本地化=============

一、自定义错误信息
        在上一篇文章中所做的验证,在界面上提示的信息都是系统自带的,有些读起来比较生硬。比如:

        如果你的环境是英文的,那么你的提示信息就是中英文夹杂的了。
 
        在这种情况下就需要用到自定义错误信息了。其实很简单,就是在model的验证特性中加上[ErrorMessage]。比如:
Model:
复制代码
        [Required(ErrorMessage = "用户名不能为空!")] 
        [Display(Name = "用户名")]

        [Remote("CheckUserName","Account")]

        public string UserName { get; set; }
复制代码

 

验证结果:

        ErrorMessage允许开发者使用{0}占位符来显示字段的显示名(即 [Display(Name = "用户名")]),如果没有Display特性,那么会显示属性名。如:
Model:
复制代码
        [Required(ErrorMessage = "{0}不能为空!")] 
        [Display(Name = "用户名")]

        [Remote("CheckUserName","Account")]

        public string UserName { get; set; }
复制代码

 

验证结果:

若为:
复制代码
        [Required(ErrorMessage = "{0}不能为空!")] //[Display(Name = "用户名")]

        [Remote("CheckUserName","Account")]

        public string UserName { get; set; }
复制代码

 

则验证结果为:

        如果验证的特性中还有其他参数,那么ErrorMessage可以用占位符直接显示其他参数,如
Model:
复制代码
        [Required]

        [StringLength(100, ErrorMessage = "请输入{2}到{1}位的{0}。", MinimumLength = 6)] 
        [DataType(DataType.Password)]

        [Display(Name = "密码")]

        public string Password { get; set; }
复制代码

 

验证结果:

 
 
二、错误信息的本地化
        如果你做的项目是要分发到不同的国家,那么就需要做本地化。而对于错误信息而言,也有这样的功能,方法如下:
        1、在项目中添加两个资源文件ErrorMessages.resx以及ErrorMessages.en-US.resx:

        2、在两个资源文件中都加入名称为UserNameRequire的资源,值分别为中英文下的提示信息:

        
        3、在web.config的 <system.web>节点加入 <globalization uiCulture="auto"/>,随着浏览器的设置来更换资源文件。
        4、在Model中也如如下代码:
        [Required(ErrorMessageResourceType = typeof(ErrorMessages), ErrorMessageResourceName = "UserNameRequire")]

        [Display(Name = "用户名")]

        public string UserName { get; set; }

 

        5、运行结果:
中文环境下:

英文环境下:

 
        好了,mvc3中错误信息的自定义和本地化比较简单,暂时总结这么多,下一篇就要讲自定义数据验证了。


===========三、自定义数据注解=============

前两节讲的都是asp.net mvc3预先设定的数据注解,但是系统自由的数据注解肯定不适合所有的场合,所以有时候我们需要自定义数据注解。
        自定义数据注解有两种,一种是直接写在模型对象中,这样做的好处是验证时只需要关心一种模型对象的验证逻辑,缺点也是显而易见的,那就是不能重用。
                                            还有一种是封装在自定义的数据注解中,优点是可重用,缺点是需要应对不同类型的模型。
        现在我们以封装在自定义数据注解中的方法为例看下如何在asp.net mvc3中自定义数据注解以及使用。
 
一、自定义属性级别的验证
        首先,所有的数据注解都应继承于 System.ComponentModel.DataAnnotations命名空间中的 ValidationAttribute类。
            重写其 protected virtual ValidationResult IsValid(object value, ValidationContext validationContext);
例如:
        我们需要写一个UserName不能超过10个字母的数据注解(你可能会说这不是有的 StringLength么,好吧,仅以此为例,我真没想到其他的需要自定义数据注解的好例子)。
        (1)新建一个类 MaxLengthAttribute,代码如下:
复制代码
    public class MyMaxLengthAttribute : ValidationAttribute
    {
        private readonly int MaxLength;
 
        public MyMaxLengthAttribute(int maxLength)
        {
            MaxLength = maxLength;
        }
 
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            string content = value.ToString();
            if (content.Length > MaxLength)
            {
                return new ValidationResult("输入的字符太多了!^_^");
            }
            return ValidationResult.Success;
            //return base.IsValid(value, validationContext);
        }
复制代码
        第二步就是像正常使用asp.net自带的数据注解一样使用,如:
        
        [Required(ErrorMessageResourceType=typeof(ErrorMessage),ErrorMessageResourceName="UserRequire")]
        [Display(Name = "用户名")]
        [MyMaxLengthAttribute(10)]
        [Remote("CheckUserName","Account", HttpMethod="POST")]
        public string UserName { get; set; }
        好了,只需要这样简单的两步就可以实现了。

验证结果:
        对于自定义的数据注解由于是继承于 System.ComponentModel.DataAnnotations命名空间中的 ValidationAttribute类,所以它的一些属性也可以使用,比如ErrorMessage,如:
        [Required(ErrorMessageResourceType=typeof(ErrorMessage),ErrorMessageResourceName="UserRequire")]
        [Display(Name = "用户名")]
        [MyMaxLengthAttribute(10,ErrorMessage="{0}字数太多")]
        [Remote("CheckUserName","Account", HttpMethod="POST")]
        public string UserName { get; set; }
        需要注意的是,自定义的数据注解不支持客户端验证,所有的数据需要提交之后再服务端验证,所以如果要同时实现客户端验证需要自己写js验证。
 
但是这样的验证有一个问题,就是默认的验证信息不能实现直接显示Display Name,所以需要如下更改:
复制代码
    public class MyMaxLengthAttribute : ValidationAttribute
    {
        private readonly int MaxLength;
 
        public MyMaxLengthAttribute(int maxLength ):base("{0}的字符太多了!")
        {
            MaxLength = maxLength;
        }
 
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            string content = value.ToString();
            if (content.Length > MaxLength)
            {
                //return new ValidationResult("输入的字符太多了!^_^");
                string errorMessage = FormatErrorMessage(validationContext.DisplayName); 
                return new ValidationResult(errorMessage);
            }
            return ValidationResult.Success;
            //return base.IsValid(value, validationContext);
        }
    }
复制代码
 
 验证结果:

 
二、自定义Model级别的验证(IValidatableObject)
        这个接口是为了实现Model的自验证(self-validating)的,是asp.net mvc3 新增的验证特性。这个特性和普通数据注解的区别是普通数据注解仅仅只能验证Model的一个属性,而实现了IValidatableObject接口的自验证则在Model的级别来验证,比如验证Model的几个属性之间的关系等。
        例如,我要验证两次输入的密码相同(好吧,我又把系统自带的验证再写一遍)。
        (1)首先,要将需要验证的Model实现IValidatableObject接口。
     public class RegisterModel : IValidatableObject
        (2)在Model中实现 Validate方法:
复制代码
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContent)
        {
            if (Password != ConfirmPassword)
            {
                yield return new ValidationResult("两次输入的密码不同!", new[] { "Password" });
            }
        }
复制代码

 

        这个方法在提交Model时会自动验证两次输入的密码是否相同,如果不同则会提示,如下:

MVC3 自带数据验证_第2张图片

 
注意:1、自验证只能把方法写在需要验证的Model中,所以这种自验证的代码无法重用;
            2、自验证的返回值是 IEnumerable<ValidationResult>,而不是 ValidationResult,所以返回值可以不止一个验证错误。
            3、Validate方法没有传入value参数,也就是意味着Validate方法可以直接访问Model中的属性值。
            4、返回值使用的是yield return来构建枚举返回值,第二个参数是指定错误信息绑定的属性,因为是string数组,所以可以关联多个属性。
 

======================== 四、Remote实现多重验证==========================

        一般来说对于一个属性的验证可能需要不止一个的远程验证,比如对于用户名来说,我们需要对于它的长度做一些限制,这个可以通过StringLength特性来解决;同时还需要验证用户名不能重复,这个就需要通过Remote特性来解决。
        现在需要再添加一个验证,那就是用户名不能包含违禁词。比如......(比较敏感,就不写了。。。^_^),违禁词保存在数据库中。刚开始我觉得这个也简单,再加个Remote验证不就解决了么。。。童鞋们,有时候我们觉得很简单就能办到的事情,如果不做,永远不知道你能不能办到。所以建议大家,遇到事情不要拖拉,尽快做好。
        噼里啪啦,很快就把验证的方法写好了,然后加到Model中一看傻眼了。。。
MVC3 自带数据验证_第3张图片
        原来不支持同一个属性有两个Remote验证。。。
 
        这个时候该怎么办呢,尝试将两个验证写在同一个Remote中,但是这样的话只能显示一个ErrorMessage,被否决。(但是的我以为Remote特性的方法只能返回一个bool值,不能返回ErrorMessage)。原来验证为false时不用返回bool值,可以直接返回ErrorMessage。方法如下:
复制代码
        public JsonResult CheckUserName(string userName)
        {
            if (IsUniqueName(userName) && IsForbiddenName(userName))
            {
                return Json(true, JsonRequestBehavior.AllowGet);
            }
            else if (!IsUniqueName(userName))
            {
                return Json("用户名不唯一!", JsonRequestBehavior.AllowGet);
            }
            else
            {
                return Json("用户名不包含违禁词!", JsonRequestBehavior.AllowGet);
            }
        }
复制代码

 

        这样就可以完美解决需要多个Remote验证的问题了。

 


你可能感兴趣的:(mvc,数据验证,前后台验证)