• ASP.NET MVC3 读书笔记三(数据注解Dataannotation和验证)


     验证在表单数据来说起到非常重要的作用,一般我们的处理是通过js来进行前端的验证,对于重要的数据还进行相应的后端数据验证;

             如果觉得验证是令人望而生畏的繁琐的事情,那么值得高兴的是ASP.NET MVC框架可以帮助处理这些琐事;并且可以很好得支持前端JS验证和后端服务器验证;毕竟对于重要的表单数据来说前端JS还是只起到了进站口的检查,通过一些工具可以轻易的破掉js的验证;但对于服务器验证也并不是万无一失,只是完全强度会高很多;

             MVC主要是通过Model的方式进行数据注解和验证,那么就需要实体类的支持;我们使用EF CodeFirst来进行实体与数据库的相应交互;

    以下说明的表单提交方式为ajax提交;

    View Code
    @using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "test", Url = "/Student/SaveEmploye" }))
        {
            @Html.ValidationSummary(true)
            <div id="test">
            </div>
            <table id="ITable" border="1">
                <tr>
                    <td style=" 120px" >
                        姓名:
                    </td>
                    <td style=" 320px; text-align: left" colspan="3" >
                        @Html.EditorFor(model => model.EmployName)<font color="red">*</font>
                        @Html.ValidationMessageFor(model => model.EmployName)
                    </td>
                </tr>
                <tr>
                    <td style=" 100px" >
                        邮箱:
                    </td>
                    <td style=" 300px; text-align: left" >
                        @Html.EditorFor(model => model.Email)<font color="blue">*</font>
                        @Html.ValidationMessageFor(model => model.Email)
                    </td>
                    <td style=" 100px" >
                        QQ:
                    </td>
                    <td style=" 300px; text-align: left" >
                        @Html.EditorFor(model => model.QQ)<font color="blue">*</font>
                        @Html.ValidationMessageFor(model => model.QQ)
                    </td>
                </tr>
                <tr>
                    <td style=" 100px" >
                        家庭电话:
                    </td>
                    <td style=" 300px; text-align: left" >
                        @Html.EditorFor(model => model.HomePhone)<font color="blue">*</font>
                        @Html.ValidationMessageFor(model => model.HomePhone)
                    </td>
                    <td style=" 100px" >
                        移动电话:
                    </td>
                    <td style=" 300px; text-align: left" >
                        @Html.EditorFor(model => model.MobilePhone)<font color="blue">*</font>
                        @Html.ValidationMessageFor(model => model.MobilePhone)
                    </td>
                </tr>
            </table>  
            <div style="background-color: #efefef;  100%; height: 30px; border: 0px; margin-bottom: 0px;
                margin-top: 10px; text-align: center">
                <input type="submit" value="保存" id="save" class="btn" style=" 80px; height: 25px; margin-top: 2px; margin-left: 2px;"
                    onclick="return CheckForm('save')" />
                <input type="button" value="关闭" class="btn" style=" 80px; height: 25px; margin-top: 2px"
                    onclick="cl()" />
                <input type="button" value="刷新" class="btn" style=" 80px; height: 25px; margin-top: 2px"
                    onclick="reload.click();" />
            </div>
        }

    上面为表单内容,提交到Student的控制器中的SaveEmploye的方法(action)

    如果要在提交前,先通过js验证,必须引入如下js

    <!--页面验证-->
        <script src="/Scripts/jquery.validate.min.js" type="text/javascript"></script>
        <script src="/Scripts/jquery.validate.unobtrusive.js" type="text/javascript"></script>

    如果要接收到ajax后台的回传信息,则必须引入如下js

    <!--ajax提交SuccessCallBack-->
        <script src="/Scripts/jquery.unobtrusive-ajax.js" type="text/javascript"></script>

    以上的js前提是必须先引用jquery;

    后台保存方法为:

    View Code
    public ActionResult SaveEmploye(UserModel usermodel)
            {
                if (ModelState.IsValid)
                {
                    if (usermodel.EmployGUID == new Guid())    //新增
                    {
                        usermodel.EmployGUID = Guid.NewGuid();
                        if (usermodel.Sex == "")
                        {
                            usermodel.Sex = "男";
                        }
                        usermodel.IsDisabeld = 1;
                        usermodel.IsLocked = 1;
                        sm.SaveEmploye(usermodel);
                        return JavaScript("SuccessCallBack('" + usermodel.EmployGUID + "')");
                    }
                    else   //修改
                    {
                        usermodel.ModifiedOn = DateTime.Now;
                        sm.Update(usermodel);
                        return JavaScript("SuccessCallBack('" + usermodel.EmployGUID + "')");
                    }
                }
                return JavaScript("SuccessCallBack('error')");
            }

    做好以上工作,在可以进行相应的注解描述;

    1、  Required

    必填验证,在一般的表单中,会有一些必填项;此时我们就可以用到Required;比如用户名;

    [Required]
    public string EmployName { get; set; }

    在字段上面加上注解信息后,在ajax提交前(客户端开启js验证,并且引入上面的验证js),会自动验证

    如果,客户端禁止了js脚步执行,那么在保存方法中可以自动进行服务器验证,在上面保存方法中写上ModelState.IsValid返回true即表示服务器端的验证成功;

    如果要自定义错误的描述信息,则可以按照如下来写:

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

    如果要显示出文本框变色和红色字体提示,引入如下样式即可

    <link href="/Content/Site.css" rel="stylesheet" />

    2、  StringLength

    StringLength是对输入的字符的长度进行限制,比如

    [Required(ErrorMessage="用户名不能为空")]
            [StringLength(15,ErrorMessage="用户名长度不能操作15个字符")]
            public string EmployName { get; set; }

    此时JS如果输入的字符长度超过15就会自动提示ErrorMessage

    3、  RegularExpression

    这个在熟悉不过,是正则表达式的匹配;我们要验证email格式,就可以按如下来写了

    [RegularExpression(@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$", ErrorMessage = "邮箱格式错误")]
            public string Email { get; set; }

    可以很简单的做到邮箱的验证;

    4、  Range

    主要用于验证范围,既可以验证int的范围,也可以验证double的范围;

    [Range(typeof(decimal),"0.00","9.99")]
            public Nullable<decimal> Price { get; set; }

    就会自动的判断区间值;

    以上4个验证的命名空间在

    【using System.ComponentModel.DataAnnotations;】下面的两个,Compare、Remoto在

    【using System.Web.Mvc;】命名空间下面

    5、  Compare

    当我们需要验证两次Email一致时,就可以用到

    [RegularExpression(@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$", ErrorMessage = "邮箱格式错误")]
            public string Email { get; set; }
            [Compare("Email")]
            public string EmailConfirm { get; set; }

    6、  Remote

    用于远程验证数据,比如在录入用户的时候,要先验证用户名是否存在;此时就可以用到Remote

    [Required(ErrorMessage="用户名不能为空")]
            [StringLength(15,ErrorMessage="用户名长度不能操作15个字符")]
            [Remote("CheckEmploye","Student",ErrorMessage="已经存在相同的用户名")]
            public string EmployName { get; set; }

    RemoteCheckEmployeStudent中的一个action

    public JsonResult CheckEmploye(string userName) {
                if ("test".Equals(userName)) {
                    return Json(true, JsonRequestBehavior.AllowGet);
                }
                return Json(false, JsonRequestBehavior.AllowGet);
            }

    7、  自定义验证

    如果碰到非常个性化的验证,我们还是要进行特殊化自定义的验证;

    下面我们以用户名第一个单词必须大写来进自定义验证;

    View Code
    public class FirstUpper:ValidationAttribute
        {
            public FirstUpper() 
            :base("{0} 第一个字母必须大写")
            { 
            }
            protected override ValidationResult IsValid(object value,ValidationContext validationContext)
            {
                if (value != null)
                {
                    var indexStr=value.ToString().Substring(0,1);
                    if (!indexStr.Equals(indexStr.ToUpper()))
                    {
                        var errorMessage = FormatErrorMessage(validationContext.DisplayName);
                        return new ValidationResult(errorMessage);
                    }
                }
                return ValidationResult.Success;
            }
        }
    [FirstUpper]
            public string EmployName { get; set; }

    定义一个类,继承自ValidationAttribute,然后重写IsValid方法,IsValid中的value就是我们需要判断的值,进行相应判断处理后,返回一个ValidationResult对象就可以;

    写完以上,只能在服务器端进行验证,无法在ajax提交前进行验证;

    首先,在上面的类中,必须继承【IClientValidatable】接口并且实现接口的

    复制代码
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
            {
                var rule = new ModelClientValidationRule();
                rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
                rule.ValidationParameters.Add("res", _result);
                rule.ValidationType = "firstupper";
                yield return rule;
            }
    复制代码

    其中_result为自定义的一个属性,可以在前台js里面取到定义在rule.ValidationParameters中的键值对

    Yield为返回一个IEnumerable的迭代;

    此时只是在后台中写好相应的数据返回到js中,js中的验证还是需要我们自己写,才能进行js验证;

    Js写法如下:

    复制代码
    //实现IClientValidatable接口的客户端验证
            if ($.validator && $.validator.unobtrusive) {
                $.validator.unobtrusive.adapters.addSingleVal("firstupper","res");   //适配器  适配器名称要与服务器上的ValidationType对应
                $.validator.addMethod("firstupper", function (value, element, firstupper) {
                    var indexStr = value.substr(0, 1);
                    if (indexStr != indexStr.toLocaleUpperCase()) {
                        return false;
                    }
                    return true;
                });
            }
    复制代码

    Firstupper为后台代码中定义的rule.ValidationType;res为后台定义的键值对;第一行是将validationtype加载到validator适配器中,然后在addMethod对应即可;

    其中firstupper依然为validationtype,回调方法中的第一个value是当前输入的值,element为整个元素对象,firstupper为res对应的键值对的值;进行判断后,页面js会自动打上“EployName第一个字母必须大写”,如果在model实体上写了ErorMessage也会自动的打出自定义的错误信息;自定义验证都必须遵循相应的规范,并且自行判断实现;(js端必须引用验证js);

    以上这种写法是比较同用的自定义注解验证;

    下面可以直接在实体上面进行注解验证;

    复制代码
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
            {
                var indexStr = EmployName.ToString().Substring(0, 1);
                if (!indexStr.Equals(indexStr.ToUpper()))
                {
                    yield return new ValidationResult("EmployName 第一个字符必须大写", new[] { "EmployName" });
                }
            }
    复制代码

    在对应的实体里面实现IValidatableObject,即可直接操作实例的字段进行验证;[好像只能在服务器端验证,在js客户端的验证好像不好实现];

    具体选用哪种验证要看具体的业务需求在进行选择;

    8、  其它注解

    在实体中除了注解一些验证信息外还可以注解其它的信息,比如

    [Display(Name="用户名")]
            public string EmployName { get; set; }

    在通过labelfor的时候就会显示”用户名”,而不显示EmployName;

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

    在进行EditorForModel进行全字段映射的时候,不会映射EmployName字段

    [DisplayFormat(DataFormatString="{0:c}")]
            public decimal price { get; set; }

    在输入9.0的时候会自动格式化为$9.00

    如果写法【[DisplayFormat(ApplyFormatInEditMode=true,DataFormatString="{0:c}")]】

    则会将$9.00进行回填,所以此处应该设置为flase不回填格式化的值,回填输入的值;

    [ReadOnly(true)]
            public string EmployName { get; set; }

    设置为readonly后,页面在提交后台时,模型不会绑定新增;页面中设置为disable的input都不会重新绑定模型提交后台;

    [HiddenInput]
            public string EmployName { get; set; }

    生成为hiddeninput控件

  • 相关阅读:
    juc线程池原理(六):jdk线程池中的设计模式
    阻塞队列之一:BlockingQueue汇总
    阻塞队列之二:LinkedTransferQueue
    遍历并批量删除容器中元素出现ConcurrentModificationException原因及处置
    Spring 3.1新特性之一:spring注解之@profile
    ThreadPoolExecutor之三:自定义线程池-扩展示例
    守护线程
    cookie跨域问题汇总
    线程组ThreadGroup
    Eclipse中设置JDK、${user}变量
  • 原文地址:https://www.cnblogs.com/powerzhang/p/3117543.html
Copyright © 2020-2023  润新知