ASP.NET MVC5----常见的数据注解和验证

只要一直走,慢点又何妨。

在使用MVC模式进行开发时,数据注解是经常使用的(模型之上操作),下面是我看书整理的一些常见的用法。

什么是验证,数据注解

  • 验证
    从全局来看,发现逻辑仅是整个验证的很小的一部分。验证首先需要管理用户友好(本地化)的与验证逻辑相关的错误提示消息;当验证失败时,在把这些错误提示消息呈现给用户界面上,当然还要向用户提供从验证失败中恢复的机制。

  • 数据注解
    注解是一种通用机制,可以用来向框架注入元数据,同时,框架不只驱动元数据的验证,还可以在生成显示和编辑模型的HTML标记时使用元数据。通俗的说就是模型上面的特定标识符(具有一定意义和作用)。

验证注解的使用

数据注解定义在一般在命名空间”System.ComponentModel.DataAnnotations”提供了服务器端验证的功能,在模型属性上使用时,框架也支持客户端验证。注解后面都是可以添加错误提示语的,ErrorMessage是每个验证特性中用来设置错误提示消息的参数,比如:

    [Required(ErrorMessage = "不能为空")]
    public int Age { get; set; }
  • Required
    强调属性是必须的,不可为空。当属性中有一个是null或空时,会引发一个验证错误。

      [Required]
      public int Age { get; set; }
    
  • StringLength
    要求必须输入名字的长度。参数可以限制最小的。如下:

      [StringLength(160,MinimumLength = 3)]
      public string Name { get; set; }
    
  • RegularExpression
    正则表达式验证,比如邮箱等需要验证正则的地方。很是方便,这样就减少了服务端的验证。

      [RegularExpression(@"^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+",ErrorMessage = "邮箱输入有误,重新输入。")]        
      public string Email { get; set; }
    
  • Range
    用来指定数值类型值得最小值和最大值。主要为int类型服务。其余的也可以,需要使用构造函数的重载版本。Type参数来做。

     [Range(20,30,ErrorMessage = "年龄不符合要求")]
      public int Age { get; set; }
    

    [Range(typeof(decimal),"0.00","59.99")]
    public decimal Price { get; set; }

  • Compare
    确定两个模型属性拥有一样的值。密码的验证(输入两次,看二者是否一样。),参数为前面模型的值。

      [Required(ErrorMessage = "密码不能为空")]
      public string Password { get; set; }
      [Compare("Password")]
      public string PasswordPalt { get; set; }
    
  • Remote
    此特性利用服务器端的回调函数执行客户端的验证逻辑。通俗的说就是这个特性可以直接找到某个控制器的action并且执行其中的方法。

Andyahui
    /// <summary>
    /// 验证模型中输入的姓名是否和数据库中重复
    /// </summary>
    /// <returns></returns>
    public JsonResult CheckUserName(string username)
    {            //数据库中的相关验证
        return Json(DateTime.Now.ToString(),JsonRequestBehavior.AllowGet);
    }

    [Remote("CheckUserName", "Admin")]
    public string UserName { get; set; }

上面控制器操作会利用与UserName属性同名的参数进行验证,同时返回一个javascript object Notaion(json)对象中的布尔类型值(0/1)

  • 自定义回复消息占位符
    使用{0}占位符,来显示用户的输入,并且形成友好提示。

      [Range(20,30,ErrorMessage = "年龄{0}不符合要求")]
      public int Age { get; set; } 
    
  • 服务端的一些处理(验证与绑定)
    ASP.NET MVC的验证特性是由模型绑定器,模型元数据,模型验证器和模型状态组成。

验证和模型绑定

操作方法中添加参数这里有一个隐式地执行模型绑定,一般我们都需要这样写,这样也安全,不会说暴露出来参数。

利用UpdateModel或TryUpdateModel方法显式执行绑定

这个实际项目中使用的很少,一般都是通过隐式进行转换的。

    [HttpPost,ActionName("Create")]
    public ActionResult CreatePost(Student model)
    {
        var model2 = new Student();
        UpdateModel(model2);
        if (TryUpdateModel(model2))
        {
             
        }
        return View(model);
    }

可以看到参数中的为隐式转换,里面的model2为显式转换。if中的返回的是bool类型。模型绑定器一旦使用新值完成对模型属性的更新,就会利用当前的 模型元数据获得模型的所有验证器。MVC运行时提供了一个验证器(DataAnnotationsModelValidator)来与数据注解一同工作,这个模型验证器会找到所有的验证特性并执行它们包含的验证逻辑,模型绑定器捕获所有失败的验证规则并把它们放入模型状态中。

编程的一个重要原则是不能相信用户的输入

验证与模型状态

模型绑定的副产品是模型状态,也就是我们服务端验证的ModelState,此状态中不仅包含用户的输入,也含有每个相关属性的所有错误(与模型状态本身有关的错误),有错误,ModelState.IsValid就返回false。从而我们就可以进行验证。

    public ActionResult CreatePost(Student model)
    {
        var s=ModelState.IsValidField("UserName");
         var ss=ModelState["UserName"].Errors.Count;
        var userName = ModelState["UserName"].Errors[0].ErrorMessage;  //获取错误消息
        if (ModelState.IsValid)      //返回bool类型
        {                 
        }
        return View(model);
    }

显示和编辑注解

  • Display
    显示模型属性设置友好的“显示名称”

      [Display(Name = "姓名")]
      [StringLength(160,MinimumLength = 3)]
      public string Name { get; set; }
    
  • ScaffoldColumn
    可以隐藏HTML的辅助方法

Andyahui
    [ScaffoldColumn(false)]
    public string Address { get; set; }
  • DisplayFormat
    处理属性各种格式化选项,当属性包含空值,可以提供可选的显示文本。也可以为包含标记的属性关闭HTML编码。还可以运行时指定一个应用于属性值的格式化字符串。

      [DisplayFormat(ApplyFormatInEditMode = true,DataFormatString = "{0:c}")]
      public decimal Total { get; set; }
    
  • ReadOnly
    可以确保默认的模型绑定器不使用请求中的新值来更新属性。

  • DataType
    运行时提供关于属性的特定用途信息。String类型的属性可应用于很多场合--可以保存e-mail地址,URL或密码。

      [Required(ErrorMessage = "密码不能为空")]
      [DataType(DataType.Password)]
      public string Password { get; set; }
    

  • UIHint
    给运行时提供一个模版名称,以备调用模版辅助方法渲染输出时使用。

自定义验证逻辑

1:将验证逻辑封装在自定义的数据注解中。
2:将验证逻辑封装在模型对象中。
把验证逻辑封装在自定义的数据注解中可以轻松地实现在多个模型中重用逻辑。需要在特性内部编写代码以应对不同类型的模型中。

  • 自定义注解
    所有的验证注解特性最终都派生自基类ValidationAttribute,它是个抽象类,在System.ComponentMode.DataAnnotation中定义。同样自定义的验证逻辑必须派生自ValidationAttribute的类。且重写IsValid方法(方法里面实现我们相应的逻辑)。

需求:限制用户输入地址中单词数量,设定一个最大值。

/// <summary>
/// 自定义模型验证
/// 输入数字的单词最大数量
/// </summary>
public class MaxWordsAttribute:ValidationAttribute
{
    private readonly int _maxWord;
    public MaxWordsAttribute(int maxWord)
    {
        _maxWord = maxWord;
    }
    protected override ValidationResult IsValid(object value,ValidationContext validationContext)
    {
        if (value!=null)
        {
            //将输入转换为string类型
            var valueAsString = value.ToString();
            //使用split(' ')空格来分隔输入值,统计生成字符串的数量。对数目比较验证。
            if (valueAsString.Split(' ').Length>_maxWord)      
            {
                 return new ValidationResult("单词超过长度");  //string类型
            }
        }
        return ValidationResult.Success;         //bool类型
    }
}

第一个参数要验证对象中的值。后面进行逻辑的判断。这样做这里的错误提示不能显示到前台。我们需要修改下,使用ValidationAttrubute的ErrorMessage属性来自定义提示错误消息。

  • 修改之后

public class MaxWordsAttribute:ValidationAttribute
{
    private readonly int _maxWord;
    public MaxWordsAttribute(int maxWord)
        :base("{0} has too many words")     
    {
        _maxWord = maxWord;
    }
    protected override ValidationResult IsValid(object value,ValidationContext validationContext)
    {
        if (value!=null)
        {
            //将输入转换为string类型
            var valueAsString = value.ToString();
            //使用split(' ')空格来分隔输入值,统计生成字符串的数量。对数目比较验证。                
            if (valueAsString.Split(' ').Length>_maxWord)
            {
                var errorMessage = FormatErrorMessage(validationContext.DisplayName);
                 return new ValidationResult(errorMessage);  
            }
        }
        return ValidationResult.Success;         //bool类型
    }
}

    [MaxWords(5)]        
    public string Address { get; set; }

这样效果就会将我们基类中的错误信息显示出来。

Andyahui

我们可以模型基础上添加自定义错误显示。

    [MaxWords(5,ErrorMessage = "你输入的单词数超界限,请重新输入。")]        
    public string Address { get; set; }

Andyahui

这里需要注意这里的执行顺序,它是先执行模型上面的验证,接着在到控制器中的action中去的。利用ModelState.IsValid来进行验证。

  • 自验证模型(IValidatableObject)
    自验证模型是指一个知道如何验证自身的模型对象,可以让类实现IVaalidatableObject接口来实现对自身的验证。
 public class Information:IValidatableObject
    {
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (UserName!=null&&UserName.Split(' ').Length>5)
            {
                 yield return new ValidationResult("单词超界限了");
            }             
        }
        [Display(Name = "用户名")]
        public string UserName { get; set; }        
    }


Andyahui

其实书上面是在错误返回值中返回的是string类型的数组,如下

yield return new ValidationResult("单词超界限了",new []{"UserName"});可以我不知道从那里取出来这个错误消息。只能单独的显示出来。其实把错误消息放在数组中可以进行多模型的验证,从而统一将错误显示出来。

自己的感觉要是需要模型验证,最好还是进行第一种方法,最起码代码看起来干净,第二种给人的感觉是很乱,但是第二种适合比较模型多的场合。

我就是我,颜色不一样的烟火。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,656评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,810评论 6 342
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,246评论 11 349
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,631评论 18 399
  • 背景 iOS10之后,用户第一次安装App的时候会弹出如下的提示:
    KODIE阅读 5,438评论 0 0