zoukankan      html  css  js  c++  java
  • 浅谈在asp.net mvc3中使用IValidatableObject接口实现Model数据验证

    ASP.NET MVC3新增了许多新特性,IValidatableObject接口就是新增的诸多特性之一。ASPNET MBC3该书中是这样描述的:IValidatableObject 接口允许执行 Model 水平的验证,并且允许你提供整个模型状态的验证错误信息,或者基于 Model 的两个属性。当 Model 绑定的时候,MVC3 从 IValidatableObject 接收错误信息,在视图中使用内建的 HTML 助手时,将会自动标识或者高亮受影响的字段。

    可能有人会问了,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 String Name { 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(ValidationContext validationContext)
    28         {
    29               
    30             if (Shipping > Inventory)
    31             {
    32                 yield return new ValidationResult("出库数量不能大于库存数量", new string[] { "Shipping" });
    33             }
    34         }
    35   
    36           
    37           
    38     }


     

    Index.cshtml

    03 @model 数据验证.Product
    04   
    05 @{
    06     Layout = null;
    07 }
    08   
    09 <!DOCTYPE html>
    10   
    11 <html>
    12 <head>
    13     <title>Index</title>
    14 </head>
    15 <body>
    16     <script src="http://www.cnblogs.com/Scripts/jquery-1.4.4.min.js" type="text/javascript"></script>
    17     <script src="http://www.cnblogs.com/Scripts/jquery.validate.min.js" type="text/javascript"></script>
    18     <script src="http://www.cnblogs.com/Scripts/jquery.validate.unobtrusive.min.js" 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                 <input type="submit" value="Create" />
    51             </p>
    52         </fieldset>
    53     }
    54       
    55     <div>
    56         @Html.ActionLink("Back to List", "Index")
    57     </div>
    58       
    59 </body>
    60 </html>


    当我们输入出库的数量大于库存的数量时,那么我们会得到错误提示,OK搞定了。

    但是还有一个小问题,Validate方法中定义的错误提示,两个属性的名称是我们硬编码的,不利于我们的维护,试想假如有一天我们将Inventory和Shipping的Display属性分别改成别的名称,那么我们原来的错误提示”出库数量不能大于库存数量”就不太恰当了,为了解决这个问题,我们可以使用反射来获取这两个属性的DisplayName值,上代码:

    EntityAttribute.cs

    03 public class EntityAttribute
    04     {
    05         private Type type;
    06         public EntityAttribute(Type type)
    07         {
    08             this.type = type;
    09         }
    10         public string GetDisplayAttributeName(string propertyName)
    11         {
    12             var propertyInfo = 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 String Name { 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(ValidationContext validationContext)
    29         {
    30             Type type = typeof(Product);
    31             EntityAttribute entityAttribute=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     }

    这回终于大功告成了!

  • 相关阅读:
    win10 下安装 tesseract + tesserocr
    win 10 家庭中文版安装docker ,但是没有 Hyper-V , 这样一步搞定
    Pycharm 分屏
    cookie 和 session
    retrying 模块
    Pychram 运行程序在 run 窗口和 python console 窗口之间切换
    封装、继承、多态
    泛型、反射、注解
    多线程笔记
    多线程
  • 原文地址:https://www.cnblogs.com/hyl8218/p/2074413.html
Copyright © 2011-2022 走看看