自定义验证
在第六章,你使用下面的代码,利用MaxWordsAttribute属性来验证一个字符串中所有的单词数量:
public class MaxWordsAttribute : ValidationAttribute { public MaxWordsAttribute(int maxWords) :base(“Too many words in {0}”) { MaxWords = maxWords; } public int MaxWords { get; set; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value != null) { var wordCount = value.ToString().Split(‘‘).Length; if (wordCount > MaxWords) { return new ValidationResult( FormatErrorMessage(validationContext.DisplayName) ); } } return ValidationResult.Success; } }
你可以使用下面这段代码的属性,但是该属性只提供了服务器端的验证支持:
[Required(ErrorMessage = “An Album Title is required”)] [StringLength(160)] [MaxWords(10)] public string Title { get; set; }
为了支持客户端验证,在下章我们会讨论为你的属性实现一个接口。
IClientValidatable
IClientValidatable接口定义了一个方法:GetClientValidationRules。MVC会在验证这个对象时发现这个接口,他会调用GetClientValidationRules来检索到一个ModelClientValidationRule对象的数组。这些对象会将元数据、规则通过框架发送到客户端。
你可以用下面的代码来实现自定义验证器的接口:
public class MaxWordsAttribute : ValidationAttribute, IClientValidatable { … public IEnumerable<ModelClientValidationRule> GetClientValidationRules( ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule(); rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()); rule.ValidationParameters.Add(“wordcount”, WordCount); rule.ValidationType = “maxwords”; yield return rule; } }
你需要确认有多少信息需要在客户端进行验证:
- 如果验证失败,需要显示什么错误信息;
- 允许使用多少个字;
- 还有一段JavaScript代码的标识;
请注意,如果你需要在客户端触发多种类型的验证,你可以同时返回多个规则。
代码会从规则的ErrorMessage属性中取出错误信息。这样可让服务器的错误信息与客户端的错误信息完全匹配。ValidationParameters集合可以容纳你所需要的客户端参数,例如允许的最大字符数等。你可以把额外的参数放置到这个集合中,不但要注意它们的名称,必须符合客户端脚本中的名称。最后,在ValidationType属性会标识你需要在客户端上使用JavaScript代码。
MVC框架需要从GetClientValidationRules方法来获得规则,并序列化后设置到客户端data-属性中:
<input data-val=”true” data-val-length=”The field Title must be a string with a maximum length of 160.” data-val-length-max=”160” data-val-maxwords=”Too many words in Title” data-val-maxwords-wordcount=”10” data-val-required=”An Album Title is required” id=”Title” name=”Title” type=”text” value=”For Those About To Rock We Salute You” />
请注意,maxwords是如何将属性名对应到MaxWordsAttribute属性上的,是因为你在ValidationType属性中设置了maxwords的文本(必须注意,验证的类型和所有验证参数名必须小写,因为命名必须符合HTML属性规则)。
现在,你已经具有了客户端上的元数据,但是你仍然要编写一些脚本代码来执行验证逻辑。
自定义验证脚本代码
幸运的是,你无需为客户端data-属性中的元数据而编写任何代码,但是,依然需要在验证中填写两端代码:
- 适配器:适配器是为了匹配MVC框架的不唐突扩展部分所需要的元数据,不唐突扩展需要将data-属性中的元数据通过适配转换成为jQuery验证可以理解的值;
- 本身的验证规则:这在jQuery中被称为验证器。
这些代码都存储同一个脚本文件中,这时假设你想将代码存入由“自定义脚本”一节所创建的MusicScripts.js文件中。在这种情况下,你需要确保MusicScript.js文件会在验证脚本载入之后再进行加载。如下使用脚本配置元素进行创建:
@section scripts { <script src=”@Url.Content(“~/Scripts/jquery.validate.min.js”)” type=”text/JavaScript”></script> <script src=”@Url.Content(“~/Scripts/jquery.validate.unobtrusive.min.js”)” type=”text/JavaScript”></script> <script src=”@Url.Content(“~/Scripts/MusicScripts.js”)” type=” text/JavaScript”> </script> }
将这些引用代码加入到MusicScripts.js中,可以为你提供你需要的代码提示功能:
/// <reference path=”jquery-1.4.4.js” /> /// <reference path=”jquery.validate.js” /> /// <reference path=”jquery.validate.unobtrusive.js” />
第一部分代码是实现适配器的,MVC框架的不唐突验证扩展会在jQuery.validator.unobtrusive.adapters对象中存储所有适配器。你可以使用适配器对象公开的API来增加新的适配器,如表8-2所示:
表8-2:适配器方法
名称 | 描述 |
addBool | 为验证器的规则创建一个“开”或“关”适配器。这个方法没有额外的参数。 |
addSingleVal | 为验证器的规则创建一个从元数据匹配单个参数的适配器。 |
addMinMax | 创建一个适配器映射到一组验证规则上,做一个最小值或一个最大值对比检查。或者同时对最大值、最小值一起进行数据规则检查。 |
add | 创建一个与前面提供类型不能匹配的适配器,它需要额外的参数或额外的设置代码。 |
在验证最大值的情况下,你可以使用addSingleVal或AddMinMax方法(或add,因为它可以实现任何情况)。如果你不需要检查最小值的话,就可以使用addSingleVal的API,如下代码:
/// <reference path=”jquery-1.4.4.js” /> /// <reference path=”jquery.validate.js” /> /// <reference path=”jquery.validate.unobtrusive.js” /> $.validator.unobtrusive.adapters.addSingleVal(“maxwords”, “wordcount”);
第一个参数是适配器的名称,必须与服务器端设置规则的ValidationProperty的值相同。第二个参数是用来检索元数据的参数名称。请注意,不需要在参数名中使用data-前缀;这里的参数需要与你在服务器端设置的ValidationParameters集合中的参数名相匹配。
适配器相对比较简单,它主要目的就是为不唐突扩展定位并识别元数据。有了合适的适配器,就可以写验证。
所有验证器都在jQuery.validator对象中,与适配器对象一样,新验证器也是通过验证对象的API来添加的。该方法名是“addMethod”:
$.validator.addMethod(“maxwords”, function (value, element, maxwords) { if (value) { if (value.split(‘‘).length > maxwords) { return false; } } return true; });
这个方法需要提供两个参数:
- 验证器名称,按照惯例应与适配器名称相匹配(和服务器上的ValidationType属性相匹配);
- 验证发生时所需调用的函数。
验证函数会接受三个参数,可以返回真(验证通过)或假(验证失败):
- 方法的第一个参数将包含输入的值(例如专辑的标题);
- 方法的第二个参数是输入元素,它包含验证所需的值(在这个例子中并没有提供相应的信息);
- 方法的第三个参数是一个包含所有验证参数的数据,在这个例子中,只包含了一个验证参数(字符串的最大长度)。
虽然ASP.NET MVC中的AJAX Helper提供了大量功能,但整个生态系统需要更多的jQuery扩展。在下一节中专门讨论这个主题。