模型验证

  Asp.Net MVC在针对目标Aciton方法的某个参数实施绑定过程中会将ValueProvider提供的数据保存在当前Controller的ModelState中。具体来说,Controller的ModelState是其ViewData的一部分,它返回一个ModelStateDictionary对象,我们通常通过其IsValid方法判断是否包含的所有ModelState均有效,即请求提交的数据是否均通过验证。

  很多情况下,我们以表单的方式向服务端提交数据,如果针对参数的验证失败,相同的页面一般会再次呈现出来。那么我们在View呈现的时候如何显示验证错误消息呢?

  通常我们调用帮助类HtmlHelper和HtmlHelper<TModel>定义的扩展方法ValidationMessage和ValidationMessageFor和ValidationSummary来实现针对验证错误的呈现,我们先来看以下代码

  public class User
    {
        public int Id { get; set; }

     [DisplayName("姓名")] [Required(ErrorMessage
= "用户名不能为空")] public string UserName { get; set; }
     [DisplayName("密码")] [Required(ErrorMessage
="密码不能为空")] [MinLength(6,ErrorMessage = "密码长度必须大于6位")] public string PassWord { get; set; } [EmailAddress] public string Email { get; set; } [Phone] public string Phone { get; set; } }
@model WebApplication2.Models.User
@{
    ViewBag.Title = "Register";
}

<br />
<br />
<br />
<form method="post" action="Register">
  
    @Html.ValidationSummary()

    <div>
        @Html.LabelFor(u=>u.UserName)
        @Html.TextBox("UserName")
        @Html.ValidationMessageFor(u => u.UserName)
    </div>
    <div>
        @Html.LabelFor(u=>u.PassWord)
        @Html.TextBox("PassWord")
        @Html.ValidationMessageFor(u => u.PassWord)
    </div>
    <div>
        @Html.Label("邮箱")
        @Html.TextBox("Email")
        @Html.ValidationMessageFor(u => u.Email)
    </div>
    <div>
        @Html.Label("手机号码")
        @Html.TextBox("Phone")
        @Html.ValidationMessageFor(u => u.Phone)
    </div>
    <input type="submit" value="提交" />
</form>

  除了使用特性验证,我们可以手动验证绑定的参数,验证不通过时可以使用下面的方式将错误信息放入ModelState中。

ModelState.AddModelError("UserName", "用户名不能为空");

  但是不管怎么说,将输入参数的验证逻辑和业务逻辑定义在Action中并不是一种值得推荐的编程方式。而这也是Asp.Net MVC的Model验证系统默认支持的变成方式。命名空间 System.ComponentModel.DataAnnotations 定义了一系列具体的ValidationAttribute特性类型,常规的验证可以通过这些预定义的特性来完成,但是很多情况下我们需要通过创建自定义的ValidationAttribute特性来解决一些特殊的验证。那我们应该怎么做呢?

  我们可以定义一个继承ValidateAttribute的特性类来实现自定义的验证特性。下面我们针对“某个值必须在指定的范围内”这样的验证规则来定义我们自己的特性。

    /// <summary>
    /// 判断某个值是否在指定的范围内
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,AllowMultiple = false)]
    public class DomainAttribute : ValidationAttribute
    {
        public IEnumerable<string> Values { get; private set; }

        public DomainAttribute(params string[] values)
        {
            this.Values = values;
        }

        public override bool IsValid(object value)
        {
            if (null == value)
            {
                return true;
            }

            return this.Values.Any(item => value.ToString() == item);
        }

        public override string FormatErrorMessage(string name)
        {
            string[] values = this.Values.Select(v => string.Format("'{0}'", v)).ToArray();
            return string.Format(base.ErrorMessageString, name, string.Join(",", values));
        }
    }
public class User
    {
        public int Id { get; set; }

        [DisplayName("姓名")]
        [Required(ErrorMessage = "用户名不能为空")]
        public string UserName { get; set; }

        [DisplayName("密码")]
        [Required(ErrorMessage ="密码不能为空")]
        [MinLength(6,ErrorMessage = "密码长度必须大于6位")]
        public string PassWord { get; set; }

        [EmailAddress]
        public string Email { get; set; }

        [Domain("male","female")]
        public string Gender { get; set; }

        [Phone]
        public string Phone { get; set; }
    }

  实际上除了将验证规则通过ValidationAttribute特性直接定义在数据类型上,还可以让数据类型实现 IValidationObject 接口 或 IDataErroInfo接口,具体可以看下main代码:

public class User: IValidatableObject
    {
        public string Name { get; set; }

        public string Gender { get; set; }

        public int Age { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            User user = validationContext.ObjectInstance as User;

            if(null == user)
            {
                yield break;
            }
            if (string.IsNullOrEmpty(user.Name))
            {
                yield return new ValidationResult("Name是必须字段", new string[] { "Name" });
            }
            if(!new string[] { "M","F"}.Any(g=>string.Compare(user.Gender,g,true) == 0)){
                yield return new ValidationResult("Gender的有效值必须是'M'或'F'", new string[] { "Gender" });
            }

        }
    }
public class User : IDataErrorInfo
    {
        public string this[string columnName]
        {
            get
            {
                switch (columnName)
                {
                    case "Name":
                        if (string.IsNullOrEmpty(this.Name))
                        {
                            return "姓名不能为空";
                        }
                        return null;
                    case "Gender":
                        if (!new string[] { "M", "F" }.Any(g => string.Compare(this.Gender, g, true) == 0))
                        {
                            return "Gender的有效值必须是'M'或'F'";
                        }
                            return null;
                    default:
                        return null;
                }
            }
        }

        public string Name { get; set; }

        public string Gender { get; set; }

        public int Age { get; set; }

        [ScaffoldColumn(false)]
        public string Error { get; private set; }
    }

  最后,我们前面讲的都是在服务端做的验证,那么我们可不可以在客户端的时候就做一些必要的验证呢,答案当然是肯定的。

<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>

<script>
    $(function () {
        $("form").validate({
            rules: {
                name: { required: true },
                birthDate: { required: true, date: true },
                email: { required: true, email: true }
            },
            messages: {
                name: { required: "请输入姓名" },
                birthDate: {
                    required: "请输入出生日期",
                    date:"请输入合法日期"

                },
                email: {
                    required: "请输入Email地址",
                    email:"请输入合法的Email地址"

                }
            }
        });
    })
</script>

如果需要结合ValidateAttribute特性来做客户端验证的话,我们可以这么做,多引入一个.js文件

 

@model WebApplication2.Models.User
@{
    ViewBag.Title = "Register";
}


<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>



@using (Html.BeginForm())
{
    @Html.EditorForModel()
    <input type="submit" value="提交" />
}
public class User
    {
        public int Id { get; set; }

        [DisplayName("姓名")]
        [Required(ErrorMessage = "用户名不能为空")]
        public string UserName { get; set; }

        [DisplayName("密码")]
        [Required(ErrorMessage ="密码不能为空")]
        [MinLength(6,ErrorMessage = "密码长度必须大于6位")]
        public string PassWord { get; set; }

        [EmailAddress]
        public string Email { get; set; }

        [Domain("M","F")]
        public string Gender { get; set; }

        [Phone]
        public string Phone { get; set; }
    }


    /// <summary>
    /// 判断某个值是否在指定的范围内
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,AllowMultiple = false)]
    public class DomainAttribute : ValidationAttribute
    {
        public IEnumerable<string> Values { get; private set; }

        public DomainAttribute(params string[] values)
        {
            this.Values = values;
        }

        public override bool IsValid(object value)
        {
            if (null == value)
            {
                return true;
            }

            return this.Values.Any(item => value.ToString() == item);
        }

        public override string FormatErrorMessage(string name)
        {
            string[] values = this.Values.Select(v => string.Format("'{0}'", v)).ToArray();
            return string.Format(base.ErrorMessageString, name, string.Join(",", values));
        }
    }

 

 

  

  

 

转载于:https://www.cnblogs.com/jesen1315/p/11017532.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值