使用Attribute校验对象属性数据是否合法
一、前言
说来惭愧,做了几年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校验对象属性数据是否合法的更多相关文章
- 区分元素特性attribute和对象属性property
× 目录 [1]定义 [2]共有 [3]例外[4]特殊[5]自定义[6]混淆[7]总结 前面的话 其实attribute和property两个单词,翻译出来都是属性,但是<javascript高 ...
- PHP校验日期格式是否合法
在后端开发中,我们常常需要校验前端传入参数的合法性,如果是校验日期参数,我们可以通过下面的方法来校验: /** * 校验日期格式是否合法 * @param string $date * @param ...
- SpringMVC使用校验validator校验对象属性
1.pom.xm添加依赖 <dependency> <groupId>javax.validation</groupId> <artifactId>va ...
- js校验对象是否全部为空
function judgeIsNotBlank(obj) { var bool = true; var arr = Object.keys(obj); ; for(var key in obj){ ...
- SpringMVC学习总结(三)——Controller接口详解(2)
4.5.ServletForwardingController 将接收到的请求转发到一个命名的servlet,具体示例如下: package cn.javass.chapter4.web.servle ...
- go-common-pool设计原理分析
common-pool: 对于一些对象的频繁创建会带来很大的系统开销,并且需要对对象数量进行控制来降低资源消耗,比如数据库连接,线程等 common-pool采用了缓存思想来解决这个问题,预先把一些对 ...
- SpringMVC(4.2):Controller接口控制器详解(2)
原文出处: 张开涛 4.5.ServletForwardingController 将接收到的请求转发到一个命名的servlet,具体示例如下: package cn.javass.chapter4. ...
- Controller接口控制器2
5.ServletForwardingController 将接收到的请求转发到一个命名的servlet,具体示例如下: package cn.javass.chapter4.web.servlet; ...
- 盈创动力之 JS校验方法
var IS_NULL = 128; // 10000000var IS_FULL = 64; // 01000000var IS_HALF = 32; // 00100000var IS_ASCII ...
随机推荐
- 记录下Sublime Text Mac版的快捷键【转】
推荐使用最新版本的Chrome/Safari或者Firefox浏览器浏览此页,否则Mac按键可能无法正常展示 The Latest Version of Chrome/Safari or Firefo ...
- PHP连接SQL Server相关配置及说明
关于php怎么连接数据库,大家肯定有不同的看法,有的用wamp,有的用xamp,他们都是集成环境,方便操作.但有时,数据库的类型不同,要连接不同的数据库.今天和大家分享一下如何连接sql2000,服 ...
- padding/border与width的关系
本文讲述 padding / border 的设置后是否对 width 有影响,width 等于 auto 与 100% 的区别 CSS 框模型 (Box Model) 规定了元素框处理元素内容.内边 ...
- 万能的SqlHelper,麻麻再也不用担心用什么数据库了
以前只用一种数据库,倒也无所谓,但是再数据库切换的时候,发现代码差不多呀. 最初,两种数据库,大不了写两个SqlHelper,但是多了也就发现代码重用率太低了吧. 因此,下面的SqlHelper诞生了 ...
- C#如何静态调用C++中的方法(静态调用dll)
当我们想要在C#中使用C++项目的方法时,这个时候就可以通过调用C++项目的dll来实现,它有静态和动态调用两种方法. DLL(Dynamic Link Library)文件为动态链接库文件,又称“应 ...
- C#中正则表达式在replace中的应用!
多少年来,许多的编程语言和工具都包含对正则表达式的支持,.NET基础类库中包含有一个名字空间和一系列可以充分发挥规则表达式威力的类,而且它们也都与未来的Perl 5中的规则表达式兼容. 此外, ...
- sqlHelper做增删改查
1.把数据库里面的数据显示出来 sqlHelper怎么用:[网上可以下载,需要可以找楼主要] 1.拷贝到项目,修改它的命名空间等于当前项目名称 2.数据库的连接信息,用户名,密码,登录方式等 < ...
- [示例] Firemonkey 图片按钮(3态)
说明:Firemonkey 图片按钮(支持三种状态:MouseOver, MouseDown, MouseUp,可各别指定图片) 原码下载:[示例]TestImageButton_圖片按鈕(3态).z ...
- java移位运算符
http://www.iteye.com/topic/766461 这篇博客讲的很清楚
- 第二十六章 hystrix-dashboard + turbine
一.使用turbine的意义 引入多个hystrix stream: 1.使用hystrix-dashboard的可以添加多个stream的功能 图中添加的两个stream会在真正monitor的时候 ...