这样的验证看上去多美——在参数上应用验证特性
如果可以把基于特性的Model验证应用在参数就好了,如图:
通过右键查看定义,可以明显看出RangeAttribute是可以应用在参数上的,如图:
看到这里有木有很嗨皮,就这么简单就是实现了,咳咳如果这样就完了,那我还写这篇干嘛呢,嘻嘻..
其实这样是不会执行验证的,验证永远都是通过的,不信看图(有图才有真相):
那为啥可以应用在参数上,但是就是不执行验证呢?不要着急请听我慢慢道来。
是这样的:模型验证是在模型绑定的时候执行的,验证信息都是保存在了ModelMetadata里(看下面的图),里面只包含一些模型的验证和一起洗其他与模型相关的信息,我们定义的参数的特性属于参数信息,并不在模型元数据里面,所以验证的时候根本就没有我们定义的特性验证信息。
ModelMetadata
说道这里一切的原因都清楚,要想实现基于特性的验证应用在参数,就是简简单单把我们定义的特性放进模型元数据里就行了啊。
第一步:把参数上的特性保存起来
要想获取参数特性可以通过ParameterDescriptor来得到,如图
要想获取ParameterDescriptor可以通过ControllerActionInvoker的GetParameterValue方法获取。如图
我们通过GetparameterValue方法,把参数parameterDescription保存在路由里。
上图我们是实现了一个自定义的ActionInvoker。在Controller里有一个CreateActionInvoker方法是用来创建ActionInvoker,我们重写这个方法返回我们自定义的ActionInvoker,如图
至此参数的信息已经被我们保存起来。
第二步:把参数的特性生成ModelValidator
我们自定义一个ModelValidatorProvider来提供ModelValidator如图
ModelValidator是由ModelValidatorProvider来提供,所以我继承了DataAnnotationsModelValidatorProvider,在重写的GetValidators方法中我们将之前保存的ParameterDescriptor提取出来,从中获取attribute与已有的attributes合并,生成ModelValidator。
此刻参数上的特性已经生成ModelValidator,并保存在ModelMetadata中
第三不:注册ParameterValidationModelValidatorProvider
在注册ParameterValidationModelValidatorProvider之前需要将现有的DataAnnotationsModelValidatorProvider移除。如图:
此刻其实参数验证还是不会有效果的,原因是模型绑定是模型验证不会对简单类型实施验证。所以我要自定义一个模型绑定。
第四部:自定义模型绑定
我们继承了默认的模型绑定,重写BindModel方法,如果是复杂类型或者model为null,就直接返回model,应为我们这个只是针对简单类型验证。空也没必要验证。
第五部:实例演示,如图
ps:感谢蒋金楠老师的博客http://www.cnblogs.com/artech/archive/2012/06/11/data-annotations-model-validation-04.html