浅谈在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需要实现IValidatableObject接口,然后实现Validate这个方法。

public class Product:IValidatableObject

    {

        /// <summary>

        /// 产品名称

        /// </summary>

        [DisplayName("产品名称")]

        [AllowHtml]//允许输入html脚本

        [Required]

        public String Name { get; set; }

        /// <summary>

        /// 库存数量

        /// </summary>

        [DisplayName("库存")]

        [Required]

        public int Inventory { get; set; }



        /// <summary>

        /// 销售数量

        /// </summary>

        [DisplayName("售出")]

        [Required]

        public int Shipping { get; set; }





        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)

        {

            

            if (Shipping > Inventory)

            {

                yield return new ValidationResult("出库数量不能大于库存数量", new string[] { "Shipping" });

            }

        }



        

        

    }


 

Index.cshtml

@model 数据验证.Product



@{

    Layout = null;

}



<!DOCTYPE html>



<html>

<head>

    <title>Index</title>

</head>

<body>

    <script src="http://www.cnblogs.com/Scripts/jquery-1.4.4.min.js" type="text/javascript"></script>

    <script src="http://www.cnblogs.com/Scripts/jquery.validate.min.js" type="text/javascript"></script>

    <script src="http://www.cnblogs.com/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>

    

    @using (Html.BeginForm()) {

        @Html.ValidationSummary(true)

        <fieldset>

            <legend>Product</legend>

    

            <div class="editor-label">

                @Html.LabelFor(model => model.Name)

            </div>

            <div class="editor-field">

                @Html.EditorFor(model => model.Name)

                @Html.ValidationMessageFor(model => model.Name)

            </div>

    

            <div class="editor-label">

                @Html.LabelFor(model => model.Inventory)

            </div>

            <div class="editor-field">

                @Html.EditorFor(model => model.Inventory)

                @Html.ValidationMessageFor(model => model.Inventory)

            </div>

    

            <div class="editor-label">

                @Html.LabelFor(model => model.Shipping)

            </div>

            <div class="editor-field">

                @Html.EditorFor(model => model.Shipping)

                @Html.ValidationMessageFor(model => model.Shipping)

            </div>

    

            <p>

                <input type="submit" value="Create" />

            </p>

        </fieldset>

    }

    

    <div>

        @Html.ActionLink("Back to List", "Index")

    </div>

    

</body>

</html>




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

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

EntityAttribute.cs

public class EntityAttribute

    {

        private Type type;

        public EntityAttribute(Type type)

        {

            this.type = type;

        }

        public string GetDisplayAttributeName(string propertyName)

        {

            var propertyInfo = type.GetProperty(propertyName);

            object[] attrs = propertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true);

            return (attrs[0] as DisplayNameAttribute).DisplayName;

        }

    }
这个EntityAttribute.cs类可以返回指定模型类的指定属性的DisplayName值。

然后我们在更新我们的Product.cs代码

public class Product:IValidatableObject

    {

        /// <summary>

        /// 产品名称

        /// </summary>

        [DisplayName("产品名称")]

        [AllowHtml]//允许输入html脚本

        [Required]

        public String Name { get; set; }

        /// <summary>

        /// 库存数量

        /// </summary>

        [DisplayName("库存")]

        [Required]

        public int Inventory { get; set; }



        /// <summary>

        /// 销售数量

        /// </summary>

        [DisplayName("售出")]

        [Required]

        public int Shipping { get; set; }







        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)

        {

            Type type = typeof(Product);

            EntityAttribute entityAttribute=new EntityAttribute(type);

            PropertyInfo[] PropertyInfos= type.GetProperties();

            string shippingDisplayName = entityAttribute.GetDisplayAttributeName("Shipping");

            string inventoryDisplayName = entityAttribute.GetDisplayAttributeName("Inventory");

            if (Shipping > Inventory)

            {

                yield return new ValidationResult(string.Format("{0}数量不能大于{1}数量", shippingDisplayName, inventoryDisplayName), new string[] { "Shipping" });

            }

        }

          

    }

这回终于大功告成了!

你可能感兴趣的:(asp.net)