通过反射验证对象属性值
数据交互是WEB交互的核心功能,用户在Web页面的表单中提交数据,程序接受数据后进行相应的逻辑运算后将数据写入数据库中,在这样的应用中无论 是考虑到应用系统的安全还是用户数据的完整,我们都将对用户提交的数据信息进行相应的验证。
比如一个用户注册的交互应用:
一般会在Model层建立一个注册类
public class Register
{
public string Account { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
在UI层将页面提交来的数据对应赋予Register类实例化后的对象的属性,之后将对象传递给BLL层进行数据库的操作
Register register = new Register();
register.Account = HttpContext.Current.Request["txtAccount"].Trim();
register.Password = HttpContext.Current.Request["txtPassword"].Trim();
register.Email = HttpContext.Current.Request["txtEmail"].Trim();
在这里,我们暂不谈数据的安全性,只讨论数据的完整性,在这样的应用中Register类中的Account和Password属性,作为用户今后 登录的重要依据,是必填的,通常情况下,我们会在将参数赋值给对象属性前先进行判断是否为空的操作
string account = string.Empty;
if (!string.IsNullOrEmpty(HttpContext.Current.Request["txtAccount"]))
{
account = HttpContext.Current.Request["txtAccount"].Trim();
}
register.Account = account;
但是,当一个需要赋值的对象的属性非常多时,我们的判断工作将是灾难性的。
还好,.Net为我们提供了Attribute类(字面上解释应该叫做“属性”,但我叫它“修饰”,因为它和类的“Property”同名)
我们可以通过建立一个验证用的Attribute对象VerifyAttribute,并给Register类的属性加上 VerifyAttribute型的修饰,记录下属性的规则,比如类型、是否可以为空,最大值以及最小值等,并建立一个通过对象属性修饰 (Attribute)验证对象属性规则的类Verify,在Register对象个属性赋值好后,通过Verify的验证过程,返回验证信息。
/// <summary>
/// 实体属性验证设置特性对象
/// </summary>
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
public abstract class VerifyAttribute : Attribute
{
/// <summary>
/// 说明
/// </summary>
protected string _Explain;
/// <summary>
/// 是否可以为空
/// </summary>
protected bool _NotNull;
/// <summary>
/// 正则表达式
/// </summary>
protected string _RegexExpressions;
/// <summary>
/// 获取说明
/// </summary>
public string Explain
{
get { return _Explain; }
}
/// <summary>
/// 获取是否可以为空值
/// </summary>
public bool NotNULL
{
get { return _NotNull; }
}
/// <summary>
/// 获取验证正则表达式
/// </summary>
public string RegexExpressions
{
get { return _RegexExpressions; }
}
/// <summary>
/// 为内部字段赋值
/// </summary>
/// <param name="explain">属性说明</param>
/// <param name="notnull">是否不可为空</param>
/// <param name="regexexpressions">正则表达式,为空不验证</param>
protected void GetParam(string explain, bool notnull, string regexexpressions)
{
_Explain = explain;
_NotNull = notnull;
_RegexExpressions = regexexpressions;
}
}
/// <summary>
/// 实体字符类型属性验证设置特性对象
/// </summary>
public class VerifyString : VerifyAttribute
{
/// <summary>
/// 最大长度
/// </summary>
protected int _MaxLength;
/// <summary>
/// 获取最大长度
/// </summary>
public int MaxLength
{
get { return _MaxLength; }
}
/// <summary>
/// 为实体字符类型属性设置验证特性
/// </summary>
/// <param name="explain">属性说明</param>
/// <param name="notnull">是否可以为空</param>
/// <param name="maxlength">属性值最大长度</param>
public VerifyString(string explain, bool notnull, int maxlength)
{
_MaxLength = maxlength;
GetParam(explain, notnull, "");
}
/// <summary>
/// 为实体字符类型属性设置验证特性
/// </summary>
/// <param name="explain">属性说明</param>
/// <param name="notnull">是否可以为空</param>
public VerifyString(string explain,bool notnull) {
_MaxLength = 0;
GetParam(explain, notnull, "");
}
/// <summary>
/// 为实体字符类型属性设置验证特性
/// </summary>
/// <param name="explain">属性说明</param>
/// <param name="notnull">是否可以为空</param>
/// <param name="maxlength">属性值最大长度</param>
/// <param name="regexexpressions">正则表达式,为空不验证</param>
public VerifyString(string explain, bool notnull, int maxlength, string regexexpressions)
{
_MaxLength = maxlength;
GetParam(explain, notnull, regexexpressions);
}
}
上面两个类VerifyString继承自VerifyAttribute类,主要是用作对String类型的属性的修饰,其中加入了可通过正则表 达式进行验证的功能。
建立实现验证过程的对象
/// <summary>
/// 实例属性数据格式验证对象
/// </summary>
public class Verify {
/// <summary>
/// 验证属性数据格式,并返回验证结果
/// </summary>
/// <typeparam name="T">必须继承自BaseObject</typeparam>
/// <param name="t">要验证的实例</param>
/// <param name="separator">分割验证结果的自定义分隔符</param>
/// <returns>验证结果</returns>
public static string VerificationDataToString<T>(T t, string separator)
{
System.Type type = t.GetType();
StringBuilder strTmp = new StringBuilder();
foreach (PropertyInfo P in type.GetProperties())
{
foreach (Attribute attr in P.GetCustomAttributes(true))
{
VerifyAttribute vattr = attr as VerifyAttribute;
string typename = vattr.GetType().ToString();
typename = typename.Substring(typename.LastIndexOf(".") + 1);
object pv = P.GetValue(t, null);
if (vattr.NotNULL)
{
if (pv == null || pv.ToString() == "")
{
strTmp.AppendFormat("{0}不得为空{1}", vattr.Explain, separator);
}
}
switch (typename)
{
case "VerifyString":
VerifyString vattrs = (VerifyString) vattr;
if (pv != null)
{
if (vattrs.MaxLength > 0)
{
if (pv.ToString().Length > vattrs.MaxLength)
{
strTmp.AppendFormat("{0}长度不得超过{1},现在是{2}{3}",
vattrs.Explain,
vattrs.MaxLength,
pv.ToString().Length,
separator);
}
}
}
break;
case "VerifyDate":
break;
case "VerifyNumber":
break;
}
if(vattr.RegexExpressions != "")
{
if(pv != null)
{
if(!TestRegex(pv.ToString(), vattr.RegexExpressions))
strTmp.AppendFormat("{0}不符合格式要求{1}", vattr.Explain, separator);
}
}
}
}
if (strTmp.ToString().Length <= 0) return "";
else return strTmp.ToString().Substring(0, strTmp.ToString().LastIndexOf(separator));
}
/// <summary>
/// 通过正则检查字符中是否存在指定字符
/// </summary>
/// <param name="value">要检查的字符串</param>
/// <param name="regex">正则表达式</param>
/// <returns>真or假</returns>
private static bool TestRegex(string value, string regex)
{
return Regex.IsMatch(value, regex);
}
}
函数VerificationData(),接受一个泛型对象,并遍历对象的属性以及属性的修饰(Attribute),取出属性的值后根据修饰描 述的规则进行验证判断,最后返回验证结果。
这样,我们修改之前的Register类,为其属性加上VerifyAttribute验证规则修饰
public class Register
{
//必填,长度不得超过50字符,启用正则验证规则"^[\w|@|.|_]{2,20}$"
[VerifyString("账户", true, 50, RegularExpression.Account)]
public string Account { get; set; }
//必填,长度不得超过50字符,启用正则验证规则"^[a-zA-Z0-9]{6,20}$"
[VerifyString("密码", true, 50, RegularExpression.Password)]
public string Password { get; set; }
//必填,长度不得超过150字符,启用正则验证规则"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$"
[VerifyString("邮箱", true, 150, RegularExpression.Email)]
public string Email { get; set; }
}
在实际应用中我们通过Verify对象的VerificationData函数返回验证结果
string account = "";
string password = "$%123";
string email = "ffssfs@fdfds";
string err = string.Empty;
Register register = new Register();
register.Account = account;
register.Password = password;
register.Email = email;
err = Verify.VerificationData<Register>(register,"<br/>");
if(err == string.Empty)
{
//验证通过
}
else
{
HttpContext.Current.Response.Write(err);
err应该返回:“账号不能为空<br/>请正确填写账号<br/>请正确填写密码<br/>请正确填写邮箱”
}
代码是从之前的项目中拷贝过来的,没有再次经过测试,如果有问题请与我联系,非常感谢!!