[转载]ASP.Net MVC探索之路 Model的比较验证

[转载]ASP.Net MVC探索之路 – Model的比较验证 – Catcher In The Rye – 博客园.

WebForm有一个比较验证服务器控件CompareValidator ,可以比较两个控件的值大小或一个控件与某一个具体值的大小。可以进行string,int,double,DateTime,decimal这些数据类 型的==、!=、>、<、>=、<=比较。在ASP.NET MVC 2.0中,我们已经可以使用基于DataAnnotations的校验方式,对Model的值进行空校验(Required)、范围校验(Range)、 字符串长度校验(StringLengthAttribute)等。在ASP.NET MVC 3中,我们还可以使用CompareAttribute进行简单的相等(==)校验,但仅此而已,其他校验就没有了。
这里我们定义一个类似WebForms验证服务器控件CompareValidator的Attribule。

首先定义一个枚举表示我们要比较的数据类型:

public enum ValidationDataType : byte
{
String,Integer,Double,Date,Currency
/*Decimal*/
}

再定义一个枚举表示比较方式:

public enum ValidationCompareOperator : byte
{
Equal, NotEqual,GreaterThan,GreaterThanEqual,LessThan,LessThanEqual
}

然后当然就是主角CompareAttribute:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class CompareAttribute : ValidationAttribute
{
public string SourceProperty { get; private set; }
public string OriginalProperty { get; private set; }
public ValidationCompareOperator Operator { get; private set; }
public ValidationDataType Type{ get; private set; }

private const string _defaultErrorMessage = ‘{0}’ 与 ‘{1}’ 进行 {2} 比较失败;

public CompareAttribute(string sourceProperty, string originalProperty
, ValidationCompareOperator op, ValidationDataType type)
:
base(_defaultErrorMessage)
{
SourceProperty
= sourceProperty;
OriginalProperty
= originalProperty;
Operator
= op;
Type
= type;
}

public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
SourceProperty, OriginalProperty, Operator.ToString());
}

public override bool IsValid(object value)
{
PropertyDescriptorCollection properties
= TypeDescriptor.GetProperties(value);
object sourceProperty = properties.Find(SourceProperty, true /* ignoreCase */)
.GetValue(value);
object originalProperty = properties.Find(OriginalProperty, true /* ignoreCase */)
.GetValue(value);

return compare(sourceProperty,originalProperty);
}

private bool compare(object sourceProperty, object originalProperty)
{
int num = 0;
switch (this.Type)
{
case ValidationDataType.String:
num
= string.Compare((string)sourceProperty
, (
string)originalProperty, false, CultureInfo.CurrentCulture);
break;

case ValidationDataType.Integer:
num
= ((int)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Double:
num
= ((double)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Date:
num
= ((DateTime)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Currency:
num
= ((decimal)sourceProperty).CompareTo(originalProperty);
break;
}
switch (this.Operator)
{
case ValidationCompareOperator.Equal:
return (num == 0);

case ValidationCompareOperator.NotEqual:
return (num != 0);

case ValidationCompareOperator.GreaterThan:
return (num > 0);

case ValidationCompareOperator.GreaterThanEqual:
return (num >= 0);

case ValidationCompareOperator.LessThan:
return (num < 0);

case ValidationCompareOperator.LessThanEqual:
return (num <= 0);
}
return true;

}
}

在Model中就可以这样使用了,以下校验两次输入的密码是否一致:

[Compare(PasswordConfirm, Password, ValidationCompareOperator.Equal
,ValidationDataType.String, ErrorMessage
= 请确认两次输入的密码一致)]
public class UserInputEdit
{
[DisplayName(
登录密码)]
public string Password { get; set; }

[DisplayName(确认密码)]
public string PasswordConfirm { get; set; }
}

如果果要Model中有两个时间,开始时间和结束时间,要求结束时间必须大于开始时间:

[Compare(TimeEnd, TimeStart, ValidationCompareOperator.GreaterThan
, ValidationDataType.Date, ErrorMessage
= 结束时间必须大于开始时间)]
public class UserInputEdit
{
[DisplayName(
开始时间)]
public DateTime TimeStart { get; set; }

[DisplayName(结束时间)]
public DateTime TimeEnd { get; set; }
}

ASP.NET MVC 3也有一个CompareAttribute,但它只能进行Equals比较。同样的比较两次密码是否一致,以上代码可以写成这样:
public class UserInputEdit
{
[DisplayName(
登录密码)]
public string Password { get; set; }

[DisplayName(确认密码)]
[Compare(
Password, ErrorMessage = 请确认两次输入的密码一致)]
public string PasswordConfirm { get; set; }
}

在 我们自定义的CompareAttribute中,必须将Attribute应用于class上。如果您想像ASP.NET MVC 3中,将标记写在属性,很遗憾不行。因为ValidationResult IsValid(…)的方法在.Net 4.0才有,MVC 3也才有相应的支持。当然也可以修改我们自定义的CompareAttribute,但请注意以下代码我没测试过:

代码

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field
, AllowMultiple
= true)]
public class CompareAttribute : ValidationAttribute
{
public string OriginalProperty { get; private set; }
public ValidationCompareOperator Operator { get; private set; }
public ValidationDataType Type{ get; private set; }

private const string _defaultErrorMessage = ‘{0}’ 与 ‘{1}’ 进行 {2} 比较失败;

public CompareAttribute(string originalProperty
, ValidationCompareOperator op, ValidationDataType type)
:
base(_defaultErrorMessage)
{
OriginalProperty
= originalProperty;
Operator
= op;
Type
= type;
}

public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
name, OriginalProperty, Operator.ToString());
}

protected override ValidationResult IsValid(object value
, ValidationContext validationContext)
{
PropertyInfo originalProperty
= validationContext.ObjectType
.GetProperty(
this.OriginalProperty);
object originalValue = originalProperty.GetValue(validationContext.ObjectInstance, null);

if(!compare(value, originalValue))
return new ValidationResult(this.FormatErrorMessage(validationContext
.DisplayName));

return null;
}

private bool compare(object sourceProperty, object originalProperty)
{
int num = 0;
switch (this.Type)
{
case ValidationDataType.String:
num
= string.Compare((string)sourceProperty
, (
string)originalProperty, false, CultureInfo.CurrentCulture);
break;

case ValidationDataType.Integer:
num
= ((int)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Double:
num
= ((double)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Date:
num
= ((DateTime)sourceProperty).CompareTo(originalProperty);
break;

case ValidationDataType.Currency:
num
= ((decimal)sourceProperty).CompareTo(originalProperty);
break;
}
switch (this.Operator)
{
case ValidationCompareOperator.Equal:
return (num == 0);

case ValidationCompareOperator.NotEqual:
return (num != 0);

case ValidationCompareOperator.GreaterThan:
return (num > 0);

case ValidationCompareOperator.GreaterThanEqual:
return (num >= 0);

case ValidationCompareOperator.LessThan:
return (num < 0);

case ValidationCompareOperator.LessThanEqual:
return (num <= 0);
}
return true;

}
}

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏