ASP.NET MVC加上Entity Framework已经是微软平台下Web开发的利器。通过为实体类添加验证属性,可以非常方便的对用户输入从客户端和服务器端进行双重验证,同时这一套机制还极具扩展性,我们可以用标准方式添加我们自己的验证属性,使其行为和表现与标配的验证属性一致。下面我打算创建一个验证电话号码的验证属性。
这里其实没有什么复杂的逻辑,直接上代码会更清晰。首先我定义了一个PhoneType枚举,用来定义需要验证的电话号码类型。这里暂时只有一种:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace CAF.Business.Validations { public enum PhoneType { Us334Dash } }
然后是验证属性类PhoneValidationAttribute,在定义实体类的时候就是通过这个属性(Attribute)来标识需要验证电话号码的实体类属性(Property)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ComponentModel.DataAnnotations;using System.Text.RegularExpressions;namespace CAF.Business.Validations { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true) ] public class PhoneValidationAttribute : ValidationAttribute { public PhoneType PhoneType { get ; set ; } public PhoneValidationAttribute ( ) { PhoneType = PhoneType.Us334Dash; } public override bool IsValid (object value ) { if (value == null ) return true ; string phone = value .ToString(); if (phone == string .Empty) return true ; string validationPattern = string .Empty; switch (PhoneType) { case PhoneType.Us334Dash: default : validationPattern = @"^\d{3}-\d{3}-\d{4}$" ; break ; } Regex regex = new Regex(validationPattern); return regex.IsMatch(phone); } } }
需要说明的是,利用PhoneValidationAttribute类我们只能做到服务器端验证。那如何做到客户端验证呢?那需要一些额外的步骤。
首先,我们需要一个ModelValidator类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Web.Mvc;using CAF.Business.Validations;namespace Synvata.Web.Validations { public class PhoneModelValidator : DataAnnotationsModelValidator<PhoneValidationAttribute> { private readonly PhoneType _PhoneType; private readonly string _ErrMsg; public PhoneModelValidator (ModelMetadata metadata, ControllerContext context, PhoneValidationAttribute attribute ) : base (metadata, context, attribute ) { _PhoneType = attribute.PhoneType; if (string .IsNullOrEmpty(attribute.ErrorMessage) == false ) _ErrMsg = attribute.ErrorMessage; else _ErrMsg = string .Format("{0} is not a valid phone number. Please enter in this format: nnn-nnn-nnnn" , metadata.GetDisplayName()); } public override IEnumerable<ModelClientValidationRule> GetClientValidationRules ( ) { ModelClientValidationRule rule = new ModelClientValidationRule(); rule.ErrorMessage = _ErrMsg; rule.ValidationType = "validatephone" ; rule.ValidationParameters.Add("phonetype" , _PhoneType.ToString()); yield return rule; } } }
定义这个类的时候需要用到前面的PhoneValidationAttribute类,另外注意,定义默认的错误信息时,用到了metadata.GetDisplayName(),这样可以取到实体类属性上定义的”Display”属性(Attribute)的值。ModelClientValidationRule的ValidationType属性和ValidationParameters是定义客户端jQuery Validation组件相关的验证函数和参数。
然后,我们需要在Global.asax.cs中的Application_Start方法内进行注册:
1 2 3 4 5 6 7 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start ( ) { DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof (PhoneValidationAttribute), typeof (PhoneModelValidator)); } }
最后就是添加客户端的验证函数,这里我偷懒了,没有用到phonetype参数:
1 2 3 4 5 6 7 8 9 10 $.validator.addMethod("validatephone" , function (value, element, phonetype ) { if (this .optional(element)) return true ; var phoneRe = /^\d{3}-\d{3}-\d{4}$/ return phoneRe.test(value); }); $.validator.unobtrusive.adapters.addSingleVal("validatephone" , "phonetype" );
这里需要2步,第一步,为jQuery Validation添加新的验证函数,第二步,把前面的验证函数注册到微软扩展的unobtrusive上,至于addSingleVal等方法的使用,可以看看源代码或者Google一下。
至此,大功告成。