您的位置:首页 > 编程语言 > ASP

asp.net mvc源码分析-ModelValidatorProviders 客户端的验证

2016-04-02 11:22 411 查看
几年写过asp.net mvc源码分析-ModelValidatorProviders 当时主要是考虑mvc的流程对,客户端的验证也只是简单的提及了一下,现在我们来仔细看一下客户端的验证。

public class RangeAttributeAdapter : DataAnnotationsModelValidator<RangeAttribute> {
public RangeAttributeAdapter(ModelMetadata metadata, ControllerContext context, RangeAttribute attribute)
: base(metadata, context, attribute) {
}

public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
string errorMessage = ErrorMessage; // Per Dev10 Bug #923283, need to make sure ErrorMessage is called before Minimum/Maximum
return new[] { new ModelClientValidationRangeRule(errorMessage, Attribute.Minimum, Attribute.Maximum) };
}
}
public class ModelClientValidationRangeRule : ModelClientValidationRule {
public ModelClientValidationRangeRule(string errorMessage, object minValue, object maxValue) {
ErrorMessage = errorMessage;
ValidationType = "range";
ValidationParameters["min"] = minValue;
ValidationParameters["max"] = maxValue;
}
}


View Code
这里的AttributeFactories可以通过

public static void RegisterAdapter(Type attributeType, Type adapterType)

public static void RegisterAdapterFactory(Type attributeType, DataAnnotationsModelValidationFactory factory)

这2个方法添加新的成员。而ValidatableFactories默认是没有成员的,可以通过以下方法添加成员

public static void RegisterValidatableObjectAdapter(Type modelType, Type adapterType)

public static void RegisterValidatableObjectAdapterFactory(Type modelType, DataAnnotationsValidatableObjectAdapterFactory factory)

注意以下我们一般自定义的验证类都是继承ValidationAttribute的,所以这里用的就是DefaultAttributeFactory,也就是DataAnnotationsModelValidator,那么就是要调用DataAnnotationsModelValidator的GetClientValidationRules方法。

public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
IEnumerable<ModelClientValidationRule> results = base.GetClientValidationRules();

IClientValidatable clientValidatable = Attribute as IClientValidatable;
if (clientValidatable != null) {
results = results.Concat(clientValidatable.GetClientValidationRules(Metadata, ControllerContext));
}

return results;
}

这个方法首先调用基类的GetClientValidationRules方法,返回没有元素的一个集合,然后调用我们自定义类的GetClientValidationRules方法,这里也就解释了为什么 我们需要实现IClientValidatable 这个接口了。注意以下DataAnnotationsModelValidator类还有一个 public override IEnumerable<ModelValidationResult> Validate(object container)这个方法,就是我们服务器端的验证,比如会调用我们子类的 public override bool IsValid(object value)方法。

在实际开发中我一般喜欢用ValidationAttribute和IClientValidatable这种方式,当然还可以用Attribute-》ModelValidator-》AssociatedValidatorProvider 比如MVC中的扩展点(九)验证 最后在调用ModelValidatorProviders.Providers.Add(new ConfirmValidatorProvider());来添加ValidatorProvider。

ModelValidatorProviders主要关心2个地方,1是获取ModelMetadata;

var metadataProvider = new DataAnnotationsModelMetadataProvider();
var metadata = metadataProvider.GetMetadataForType(null, section.SectionDataType);

foreach (ModelMetadata meta in metadata.Properties)
{
var validatorList = meta.GetValidators(this.ControllerContext).ToList();
if (validatorList.Count > 0)
{
foreach (var validator in validatorList)
{
var rules = validator.GetClientValidationRules();
foreach (var rule in rules)
{
object value;
switch (rule.ValidationType)
{
case "required":
XXXXXXX
break;
}
}
}
}
}


2是如何调用GetClientValidationRules方法。

ModelMetadata是一个很复杂的东西,所以本文没有提及,大家可以参考:

ASP.NET MVC Model元数据(一)

ASP.NET MVC Model元数据(二)

ASP.NET MVC Model元数据(三)

ASP.NET MVC Model元数据(四)

ASP.NET MVC Model元数据(五)

客户端的验证就相对简单了很多,我们先说这一段code:

jQuery.validator.unobtrusive.adapters.add('mulregular', ['regexs', 'minmatchno'], function (options) {
options.rules["mulregular"] = {
regexs: options.params.regexs,
minmatchno: options.params.minmatchno
};
if (options.message) {
options.messages['mulregular'] = options.message;
}
});

其中的Add的实现如下:

adapters.add = function (adapterName, params, fn) {
if (!fn) { // Called with no params, just a function
fn = params;
params = [];
}
this.push({ name: adapterName, params: params, adapt: fn });
return this;
};

而我们定义的这个方法在parseElement方法中调用:

$.each(this.adapters, function () {
var prefix = "data-val-" + this.name, //获取验证前缀 如data-val-mulregular
message = $element.attr(prefix),// 获取error message
paramValues = {};

if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
prefix += "-";

$.each(this.params, function () { //params就是传递的['regexs', 'minmatchno']
paramValues[this] = $element.attr(prefix + this);// 获取参数值 如data-val-mulregular-minmatchno 这里的this就是minmatchno
});

this.adapt({ //调用我们在jQuery.validator.unobtrusive.adapters.add定义的方法
element: element,
form: form,
message: message,
params: paramValues,
rules: rules,
messages: messages
});
}



再来看客户端验证的实现code:

jQuery.validator.addMethod('mulregular', function (value, element, param) {
if (this.optional(element)) {
return true;
}
var regs = param["regexs"].split(",");
var minmatchno = param["minmatchno"] - 0;
for (var i = 0; i < regs.length; i++) {
var match = new RegExp(regs[i]).exec(value);
if (match && (match.index === 0) && (match[0].length === value.length)) {
minmatchno -= 1;
}
}
return minmatchno <= 0;
});

其中addMethod的实现很简单

addMethod: function( name, method, message ) {
$.validator.methods[name] = method;
$.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];
if ( method.length < 3 ) {
$.validator.addClassRules(name, $.validator.normalizeRule(name));
}
}

这里定义的方法在check里面调用:



大家看到的这里的parameter的数据和我们在unobtrusive.adapters中返回的参数一致,但是怎么获取的我也不是很明白。里面涉及到的内容很多很多。

网上关于这一方面的还很多

ASP.NET MVC Unobtrusive JavaScript 实现 onfocusout 验证, onfocusin 清除错误

ASP.NET MVC的客户端验证:jQuery验证在Model验证中的实现

改写jquery.validate.unobtrusive.js实现气泡提示mvc错误

Query validate 根据 asp.net MVC的验证提取简单快捷的验证方式(jquery.validate.unobtrusive.js)

ASP.NET MVC如何实现自定义验证(服务端验证+客户端验证)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: