浅谈在asp.net mvc3中使用IValidatableObject接口实现Model数据验证
2011-06-07 16:23
459 查看
ASP.NETMVC3新增了许多新特性,IValidatableObject接口就是新增的诸多特性之一。ASPNETMBC3该书中是这样描述的:IValidatableObject接口允许执行Model水平的验证,并且允许你提供整个模型状态的验证错误信息,或者基于Model的两个属性。当Model绑定的时候,MVC3从IValidatableObject接收错误信息,在视图中使用内建的HTML助手时,将会自动标识或者高亮受影响的字段。
可能有人会问了,Mvc2中可以使用自定义验证来对模型进行验证,为什么mvc3中又新增了IValidatableObject这个借口呢?
不错,我们是可以通过继承ValidationAttribute类并且重写它的IsValid方法来自定义验证,但是这中做法有个局限性,那就是如果我需要验证模型的各个属性之间的逻辑关系,例如:我们有一个商品模型,我们要求这个模型的出库数量不能大于库存数量,那么自定义验证就显得不是那么给力了,这时候我们就需要ValidationAttribute接口了。
首先我们这个商品模型Product.cs需要实现ValidationAttribute接口,然后实现Validate这个方法。
viewsourceprint?
Index.cshtml
viewsourceprint?
当我们输入出库的数量大于库存的数量时,那么我们会得到错误提示,OK搞定了。
但是还有一个小问题,Validate方法中定义的错误提示,两个属性的名称是我们硬编码的,不利于我们的维护,试想假如有一天我们将Inventory和Shipping的Display属性分别改成别的名称,那么我们原来的错误提示”出库数量不能大于库存数量”就不太恰当了,为了解决这个问题,我们可以使用反射来获取这两个属性的DisplayName值,上代码:
EntityAttribute.cs
viewsourceprint?
然后我们在更新我们的Product.cs代码
viewsourceprint?
这回终于大功告成了!
可能有人会问了,Mvc2中可以使用自定义验证来对模型进行验证,为什么mvc3中又新增了IValidatableObject这个借口呢?
不错,我们是可以通过继承ValidationAttribute类并且重写它的IsValid方法来自定义验证,但是这中做法有个局限性,那就是如果我需要验证模型的各个属性之间的逻辑关系,例如:我们有一个商品模型,我们要求这个模型的出库数量不能大于库存数量,那么自定义验证就显得不是那么给力了,这时候我们就需要ValidationAttribute接口了。
首先我们这个商品模型Product.cs需要实现ValidationAttribute接口,然后实现Validate这个方法。
03 | public class Product:IValidatableObject |
04 | { |
05 | ///<summary> |
06 | ///产品名称 |
07 | ///</summary> |
08 | [DisplayName( "产品名称" )] |
09 | [AllowHtml] //允许输入html脚本 |
10 | [Required] |
11 | public StringName{ get ; set ;} |
12 | ///<summary> |
13 | ///库存数量 |
14 | ///</summary> |
15 | [DisplayName( "库存" )] |
16 | [Required] |
17 | public int Inventory{ get ; set ;} |
18 |
19 | ///<summary> |
20 | ///销售数量 |
21 | ///</summary> |
22 | [DisplayName( "售出" )] |
23 | [Required] |
24 | public int Shipping{ get ; set ;} |
25 |
26 |
27 | public IEnumerable<ValidationResult>Validate(ValidationContextvalidationContext) |
28 | { |
29 |
30 | if (Shipping>Inventory) |
31 | { |
32 | yield return new ValidationResult( "出库数量不能大于库存数量" , new string []{ "Shipping" }); |
33 | } |
34 | } |
35 |
36 |
37 |
38 | } |
03 | @model数据验证.Product |
04 |
05 | @{ |
06 | Layout= null ; |
07 | } |
08 |
09 | <!DOCTYPEhtml> |
10 |
11 | <html> |
12 | <head> |
13 | <title>Index</title> |
14 | </head> |
15 | <body> |
16 | <scriptsrc= " type= "text/javascript" ></script> |
17 | <scriptsrc= " type= "text/javascript" ></script> |
18 | <scriptsrc= " type= "text/javascript" ></script> |
19 |
20 | @ using (Html.BeginForm()){ |
21 | @Html.ValidationSummary( true ) |
22 | <fieldset> |
23 | <legend>Product</legend> |
24 |
25 | <div class = "editor-label" > |
26 | @Html.LabelFor(model=>model.Name) |
27 | </div> |
28 | <div class = "editor-field" > |
29 | @Html.EditorFor(model=>model.Name) |
30 | @Html.ValidationMessageFor(model=>model.Name) |
31 | </div> |
32 |
33 | <div class = "editor-label" > |
34 | @Html.LabelFor(model=>model.Inventory) |
35 | </div> |
36 | <div class = "editor-field" > |
37 | @Html.EditorFor(model=>model.Inventory) |
38 | @Html.ValidationMessageFor(model=>model.Inventory) |
39 | </div> |
40 |
41 | <div class = "editor-label" > |
42 | @Html.LabelFor(model=>model.Shipping) |
43 | </div> |
44 | <div class = "editor-field" > |
45 | @Html.EditorFor(model=>model.Shipping) |
46 | @Html.ValidationMessageFor(model=>model.Shipping) |
47 | </div> |
48 |
49 | <p> |
50 | <inputtype= "submit" value= "Create" /> |
51 | </p> |
52 | </fieldset> |
53 | } |
54 |
55 | <div> |
56 | @Html.ActionLink( "BacktoList" , "Index" ) |
57 | </div> |
58 |
59 | </body> |
60 | </html> |
但是还有一个小问题,Validate方法中定义的错误提示,两个属性的名称是我们硬编码的,不利于我们的维护,试想假如有一天我们将Inventory和Shipping的Display属性分别改成别的名称,那么我们原来的错误提示”出库数量不能大于库存数量”就不太恰当了,为了解决这个问题,我们可以使用反射来获取这两个属性的DisplayName值,上代码:
EntityAttribute.cs
03 | public class EntityAttribute |
04 | { |
05 | private Typetype; |
06 | public EntityAttribute(Typetype) |
07 | { |
08 | this .type=type; |
09 | } |
10 | public string GetDisplayAttributeName( string propertyName) |
11 | { |
12 | varpropertyInfo=type.GetProperty(propertyName); |
13 | object []attrs=propertyInfo.GetCustomAttributes( typeof (DisplayNameAttribute), true ); |
14 | return (attrs[0] as DisplayNameAttribute).DisplayName; |
15 | } |
16 | } |
这个EntityAttribute.cs类可以返回指定模型类的指定属性的DisplayName值。
然后我们在更新我们的Product.cs代码
03 | public class Product:IValidatableObject |
04 | { |
05 | ///<summary> |
06 | ///产品名称 |
07 | ///</summary> |
08 | [DisplayName( "产品名称" )] |
09 | [AllowHtml] //允许输入html脚本 |
10 | [Required] |
11 | public StringName{ get ; set ;} |
12 | ///<summary> |
13 | ///库存数量 |
14 | ///</summary> |
15 | [DisplayName( "库存" )] |
16 | [Required] |
17 | public int Inventory{ get ; set ;} |
18 |
19 | ///<summary> |
20 | ///销售数量 |
21 | ///</summary> |
22 | [DisplayName( "售出" )] |
23 | [Required] |
24 | public int Shipping{ get ; set ;} |
25 |
26 |
27 |
28 | public IEnumerable<ValidationResult>Validate(ValidationContextvalidationContext) |
29 | { |
30 | Typetype= typeof (Product); |
31 | EntityAttributeentityAttribute= new EntityAttribute(type); |
32 | PropertyInfo[]PropertyInfos=type.GetProperties(); |
33 | string shippingDisplayName=entityAttribute.GetDisplayAttributeName( "Shipping" ); |
34 | string inventoryDisplayName=entityAttribute.GetDisplayAttributeName( "Inventory" ); |
35 | if (Shipping>Inventory) |
36 | { |
37 | yield return new ValidationResult( string .Format( "{0}数量不能大于{1}数量" ,shippingDisplayName,inventoryDisplayName), new string []{ "Shipping" }); |
38 | } |
39 | } |
40 |
41 | } |
相关文章推荐
- 浅谈在asp.net mvc3中使用IValidatableObject接口实现Model数据验证
- ASP.NET MVC3 中使用IValidatableObject接口实现Model数据验证
- MVC学习十一:浅谈在ASP.NET MVC3中使用IClientValidatable接口实现客户端和服务器端同时验证
- 浅谈在ASP.NET MVC3中使用IClientValidatable接口实现客户端和服务器端同时验证
- 浅谈在ASP.NET MVC3中使用IClientValidatable接口实现客户端和服务器端同时验证
- 浅谈在ASP.NET MVC3中使用IClientValidatable接口实现客户端和服务器端同时验证
- ASP.NET MVC3中使用IClientValidatable接口实现客户端和服务器端同时验证
- 使用httppost 实现高效的数据交互接口
- 【转】MetadataType的使用,MVC的Model层数据验证
- 浅谈在JAVA中使用接口引用实现类
- HTML5 使用application cache 接口实现离线数据缓存
- Jeeplus框架SSM+shiro权限控制中实现跳过登录验证访问接口数据
- Android开发:使用序列化接口Parcelable、Serializable实现Activity间传递复杂数据类型参数
- MetadataType的使用,MVC的Model层数据验证
- 使用PrepareStatement接口,实现数据表的更新操作
- Dubbo工程里的数据传递实体model必须且建议只实现一种接口
- 【练习】使用接口回调和handler实现数据加载到listview
- Android开发:使用序列化接口Parcelable、Serializable实现Activity间传递复杂数据类型参数
- 使用jwt实现restful接口用户验证
- 使用JSON Schema来验证接口数据