一、前言

  说来惭愧,做了几年ASP.NET最近才有机会使用MVC开发生产项目。项目中新增、编辑表单提交存在大量服务端数据格式校验,各种if else显得代码过于繁琐,特别是表单数据比较多的时候尤为恶心,正好今天比较闲就写了一个Demo,统一验证Model层中的数据格式。在此说明一下,MVC自带数据检验功能同时还能主动通知到前端显示,个人感觉不太好用的样子(并没有深入研究),而且公司项目并没有使用MVC的辅助方法生成View,不知道MVC的数据校验功能能否起作用。

二、目标

  通过调用对象的Validate方法,校验对象的属性是否全部合法,否则返回一条失败信息。

三、文件结构

  

四、实现

  1、因为并不是所有的Model都应该有Validate方法,同时Validate方法的逻辑代码也是唯一的(解析对象属性上的特性,根据特性描述的规则校验数据是否合法),因此定义接口IValidate,并为IValidate绑定扩展方法Validate,待校验Model继承自IValidate接口(数据解析使用到的特性定义代码在后面)

public interface IValidate
{
}
public static class ValidateExtension
{
/// <summary>
/// 校验对象属性值是否合法
/// </summary>
/// <param name="obj">待校验对象</param>
/// <returns></returns>
public static ValidateResult Validate(this IValidate obj)
{
ValidateResult result = new ValidateResult(); PropertyInfo[] infos = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo p in infos)
{
//获取数据校验特性。
Attribute[] attrs = Attribute.GetCustomAttributes(p, typeof(ValidateAttribute), false);
if (attrs.Length <= )
{
continue;
} //获取名称描述特性
CaptionAttribute caption = Attribute.GetCustomAttribute(p, typeof(CaptionAttribute), false) as CaptionAttribute;
object value = p.GetValue(obj); foreach (Attribute attr in attrs)
{
ValidateAttribute validate = attr as ValidateAttribute;
if (validate == null)
{
continue;
} result = Validate(validate, value, caption);
if (!result.IsSuccess)
{
return result;
}
}
}
return result;
} /// <summary>
/// 校验数据是否合法
/// </summary>
/// <param name="validate">校验规则</param>
/// <param name="value">待校验值</param>
/// <param name="caption">描述</param>
/// <returns></returns>
static ValidateResult Validate(ValidateAttribute validate, object value, CaptionAttribute caption)
{
ValidateResult result = new ValidateResult(); if (!validate.Validate(value))
{
result.IsSuccess = false;
if (caption == null)
{
result.ErrorMessage = validate.GetErrorMessage();
}
else
{
result.ErrorMessage = validate.GetErrorMessage(caption.Name);
}
}
return result;
}
}

  2、定义特性,首先我们应该需要一个描述属性名称的特性CaptionAttribute,用来描述该属性的名称,使得数据异常提示更为友好。

[AttributeUsage(AttributeTargets.Property)]
public class CaptionAttribute : Attribute
{
/// <summary>
/// 构造方法
/// </summary>
/// <param name="name">属性名称</param>
public CaptionAttribute(string name)
{
this.Name = name;
} /// <summary>
/// 属性名称
/// </summary>
public string Name { get; set; }
}

  3、定义特性,校验规则特性应该都有一个Validate方法,校验当前规则是否可以同过,同时我们在解析规则的时候读取属性特性也应该只读取校验相关的特性,而不是所有的。因此定义特性父类ValidateAttribute。

[AttributeUsage(AttributeTargets.Property, Inherited = true)]
public abstract class ValidateAttribute : Attribute
{
/// <summary>
/// 校验不通过提示信息
/// </summary>
protected string ErrorMessage { get; set; } /// <summary>
/// 校验数据是否合法
/// </summary>
/// <param name="value">待校验的值</param>
/// <returns></returns>
public abstract bool Validate(object value); /// <summary>
/// 获取检验不通过提示信息
/// </summary>
/// <param name="name">字段名称</param>
/// <returns></returns>
public string GetErrorMessage(string name = "")
{
if (string.IsNullOrEmpty(name))
{
name = "该字段";
} return string.Format(this.ErrorMessage, name);
}
}

  4、定义特性,创建相关的业务规则特性,为了用户使用时可自定义提示信息,应重载构造方法(此处提供值范围规则及正则验证规则)。

public class RangeAttribute : ValidateAttribute
{
private int min = -;
private int max = -; /// <summary>
/// 构造方法
/// </summary>
/// <param name="min">最小值</param>
/// <param name="max">最大值</param>
public RangeAttribute(int min, int max)
: this(min, max, string.Format("{0}应在{1}到{2}之间", "{0}", min, max))
{ } /// <summary>
/// 构造方法
/// </summary>
/// <param name="min">最小值</param>
/// <param name="max">最大值</param>
/// <param name="errorMessage">校验失败提示信息</param>
public RangeAttribute(int min, int max, string errorMessage)
{
this.min = min;
this.max = max;
this.ErrorMessage = errorMessage;
} /// <summary>
/// 校验数据是否合法
/// </summary>
/// <param name="value">待校验的值</param>
/// <returns></returns>
public override bool Validate(object value)
{
if (value == null)
{
return false;
} decimal v;
if (!decimal.TryParse(value.ToString(), out v))
{
return false;
} return v >= min && v <= max;
}
}
public class RegexAttribute : ValidateAttribute
{
private string regex = null; /// <summary>
/// 构造方法
/// </summary>
/// <param name="regex">正则</param>
public RegexAttribute(string regex)
: this(regex, "{0}格式错误")
{ } /// <summary>
/// 构造方法
/// </summary>
/// <param name="regex">正则</param>
/// <param name="errorMessage">校验失败提示信息</param>
public RegexAttribute(string regex, string errorMessage)
{
this.regex = regex;
this.ErrorMessage = errorMessage;
} /// <summary>
/// 校验数据是否合法
/// </summary>
/// <param name="value">待校验的值</param>
/// <returns></returns>
public override bool Validate(object value)
{
if (value == null)
{
return false;
} return new Regex(regex).IsMatch(value.ToString());
}
}
public class RegexExpression
{
/// <summary>
/// 手机号格式正则表达式(开放号段:13|4|5|7|8)
/// </summary>
public const string Mobile = "^1(3|4|5|7|8)\\d{9}$"; /// <summary>
/// 中文字符正则表达式(只允许输入中文且不包含任何标点符号等)
/// </summary>
public const string Chinese = "^[\u4E00-\u9FFF]+$"; /// <summary>
/// 邮箱正则表达式
/// </summary>
public const string Email = @"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$";
}

  5、Validate方法返回的结果包含是否成功以及如果失败了则返回提示信息,因此定义一个校验结果类(差点就漏了这部分代码...)。

public class ValidateResult
{
public ValidateResult()
{
this.IsSuccess = true;
} /// <summary>
/// 构造方法
/// </summary>
/// <param name="isSuccess">是否校验通过</param>
/// <param name="errorMessage">检验不通过提示信息</param>
public ValidateResult(bool isSuccess, string errorMessage)
{
this.IsSuccess = isSuccess;
this.ErrorMessage = errorMessage;
} /// <summary>
/// 是否校验通过
/// </summary>
public bool IsSuccess { get; set; } /// <summary>
/// 检验不通过提示信息
/// </summary>
public string ErrorMessage { get; set; }
}

五、使用

  1、定义Model

class User : IValidate
{
[Caption("手机号码")]
[Regex(RegexExpression.Mobile)]
public string Mobile { get; set; } [Caption("年龄")]
[Range(, )]
public int Age { get; set; } [Range(, , "身高数据异常")]
public decimal Height { get; set; }
}

  2、调用验证及输出结果

  

  

  

使用Attribute校验对象属性数据是否合法的更多相关文章

  1. 区分元素特性attribute和对象属性property

    × 目录 [1]定义 [2]共有 [3]例外[4]特殊[5]自定义[6]混淆[7]总结 前面的话 其实attribute和property两个单词,翻译出来都是属性,但是<javascript高 ...

  2. PHP校验日期格式是否合法

    在后端开发中,我们常常需要校验前端传入参数的合法性,如果是校验日期参数,我们可以通过下面的方法来校验: /** * 校验日期格式是否合法 * @param string $date * @param ...

  3. SpringMVC使用校验validator校验对象属性

    1.pom.xm添加依赖 <dependency> <groupId>javax.validation</groupId> <artifactId>va ...

  4. js校验对象是否全部为空

    function judgeIsNotBlank(obj) { var bool = true; var arr = Object.keys(obj); ; for(var key in obj){ ...

  5. SpringMVC学习总结(三)——Controller接口详解(2)

    4.5.ServletForwardingController 将接收到的请求转发到一个命名的servlet,具体示例如下: package cn.javass.chapter4.web.servle ...

  6. go-common-pool设计原理分析

    common-pool: 对于一些对象的频繁创建会带来很大的系统开销,并且需要对对象数量进行控制来降低资源消耗,比如数据库连接,线程等 common-pool采用了缓存思想来解决这个问题,预先把一些对 ...

  7. SpringMVC(4.2):Controller接口控制器详解(2)

    原文出处: 张开涛 4.5.ServletForwardingController 将接收到的请求转发到一个命名的servlet,具体示例如下: package cn.javass.chapter4. ...

  8. Controller接口控制器2

    5.ServletForwardingController 将接收到的请求转发到一个命名的servlet,具体示例如下: package cn.javass.chapter4.web.servlet; ...

  9. 盈创动力之 JS校验方法

    var IS_NULL = 128; // 10000000var IS_FULL = 64; // 01000000var IS_HALF = 32; // 00100000var IS_ASCII ...

随机推荐

  1. C#设置文件权限

    在开发中,我们经常会使用IO操作,例如创建,删除文件等操作.在项目中这样的需求也较多,我们也会经常对这些操作进行编码,但是对文件的权限进行设置,这样的操作可能会手动操作,现在介绍一种采用代码动态对文件 ...

  2. 【JUC】JDK1.8源码分析之ThreadPoolExecutor(一)

    一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了 ...

  3. HTML5 Application cache初探和企业应用启示

    Application Cache 在自己做的开源项目( https://github.com/etoah/Lucien ) 用到了HTML5 的Application Cache,现总结如下: 目录 ...

  4. angularjs的表单验证

    angularjs内置了常用的表单验证指令,比如min,require等.下面是演示: <!DOCTYPE html> <html> <head> <meta ...

  5. view向controller提交列表

    第一次将view中列表提交到controller,尝试了下,还是可以的 要传输的实体类 /// <summary> /// 用于展示的角色类 /// </summary> pu ...

  6. 表单填写示例(通过JavaScript访问DOM)

    自己写就的代码,再烂也是自己的- 实现代码 <!DOCTYPE html><html lang="en"><head> <meta cha ...

  7. 分页控件layui的使用

    $.getJSON( )的使用方法简介 $.getJSON( url [, data ] [, success(data, textStatus, jqXHR) ] ) url是必选参数,表示json ...

  8. 强大的自适应jQuery焦点图特效

    jQuery焦点图切换自适应效果 自适应jQuery焦点图特效是一款支持移动端的响应式jQuery焦点图插件,支持flexible布局,支持移动触摸事件等. 今天我们要来分享一款很灵活的jQuery焦 ...

  9. C# 工作中遇到的几个问题

    C#  工作中遇到的几个问题 1.将VS2010中的代码编辑器的默认字体“新宋体”改为“微软雅黑”后,代码的注释,很难对齐,特别是用SandCastle Help File Builder生成帮助文档 ...

  10. WPF筛选、排序和分组

    可以通过CollectionViewSource或者CollectionView对视图进行排序.筛选和分组. 一.通过CollectionViewSource listingDataView是Coll ...