Model验证
上节说了Asp.net MVC中Model的绑定,本节讲解下Model绑定时的数据验证。
数据结构
Model验证中的错误信息怎样存储?怎样传递给View
?
ModelError
类型每条错误信息,ModelErrorCollection
错误提示的集合,ModelState
为存储错误验证和数据源。其在参数绑定时将生成的ModelState
(验证信息和数据源)保存到了Controller
的ModelState
属性中(为ViewData
的一部分,类型为ModelStateDictionary
)。
[Serializable]
public class ModelState
{
private ModelErrorCollection _errors = new ModelErrorCollection();
public ValueProviderResult Value { get; set; }
public ModelErrorCollection Errors
{
get { return _errors; }
}
}
手工数据验证
了解验证数据传递到View
的机制,可手工写数据验证方法.添加错误信息ModelState.AddModelError(key,value)
可验类型
手工实现是麻烦的,可用通过定制数据,使数据可使用相应的验证机制ModelValidator
验证。
- 实现抽象类
ValidationAttribute
,将特性绑定到需要验证的数据上 - 实现接口
IValidatableObject
- 实现接口
IDataErrorInfo
验证验证
对Model的验证为ModelValidator
,可通过实现该抽象类实现自定义的验证策略。ModelValidator
的抽象方法为Validate
.
数据类型 | 验证方法 | validatorProvider |
---|---|---|
ValidationAttribute | DataAnnotationsModelValidator | DataAnnotationsModelValidatorProvider |
IValidatableObject | ValidatableObjectAdapter | DataAnnotationsModelValidatorProvider |
IDataErrorInfo | DataErrorInfoModelValidator | DataErrorInfoModelValidatorProvider |
跟IValueProvider
数据提供机制相似,这里有ModelValidatorProvider
为对应ModelValidator
提供器。可以通过ModelValidatorProviders
注册数据验证机制。
CompositeModelValidator执行验证的组织
CompositeModelValidator
为ModelValidator
的内部类,通过静态方法GetModelValidator
获得。
CompositeModelValidator
的Validate
会根据数据的元数据验证其属性Metadata.PropertiesAsArray
。其中ModelMetadata
的GetValidators
方法会得到其上的所有验证,注意 ModelValidatorProvider
有抽象方法public abstract IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context);
即可以通过ModelMetadata
可获得对应的验证机制
public class ModelMetadata{
public virtual IEnumerable<ModelValidator> GetValidators(ControllerContext context)
{
return ModelValidatorProviders.Providers.GetValidators(this, context);
}
}
public static class ModelValidatorProviders
{
public static ModelValidatorProviderCollection Providers
{
get { return _providers; }
}
}
验证策略
数据绑定时验证,其实验证注意验证的为复杂类型。
在DefaultModelBinder
进行BindModel
时验证并将验证信息保存到ModelState
.
OnModelUpdated(controllerContext, newBindingContext);
方法