我如何在来自资源的 DataAnnotations 错误消息中使用 DRY(不要重复自己)
How could i use DRY(don't repeat yourself) in DataAnnotations Error messages form Resourse
这是我的代码
[Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
[RegularExpression("^[0-9]*$", ErrorMessageResourceType =typeof(DCC.RegistrationVMLiterals),ErrorMessageResourceName ="MustBeNumber")]
[Display(Name = "BeneficiaryNo")]
public long BeneficiaryNo { get; set; }
[Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
[RegularExpression("^[a-zA-z]*$",ErrorMessage ="must only be letters")]
[Display(Name = "FullName")]
public string FullName { get; set; }
[Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
[Display(Name = "GenderID")]
public int GenderID { get; set; }`
试试这个,还没有测试过,但应该可以:
[AttributeUsage(AttributeTargets.Class)]
public class AggregatedRequiredAttribute: ValidationAttribute
{
private readonly string[] _propertiesToValidate;
private readonly string message = Resources.ValRequired;
public AggregatedRequiredAttribute(params string[] propertiesToValidate)
{
if (propertiesToValidate == null || !propertiesToValidate.Any()) throw new ArgumentException(nameof(propertiesToValidate));
_propertiesToValidate = propertiesToValidate;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (!validationContext.ObjectType.GetMember(validationContext.MemberName).Any())
throw new InvalidOperationException("Current type does not contain such property.");
if (!_propertiesToValidate.Contains(validationContext.MemberName))
return ValidationResult.Success;
var defaultRequired = new RequiredAttribute() {ErrorMessage = message};
return defaultRequired.IsValid(value) ? ValidationResult.Success : new ValidationResult(message);
}
}
然后你可以像这样使用它(来自默认 MVC 模板的 ViewModel):
[AggregatedRequired("Email","Password")]
public class RegisterViewModel
{
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
注意,我只使用了一次错误消息字符串,您也可以在错误消息中使用一些字母并将其动态替换为正在验证的 属性 的实际名称。
更新
我不确定第一个 if
语句,你应该测试一下。
更新 2
另外我想我用错了IsValid
方法,但思路本身很清楚。
我认为你误解了这个概念或 DRY。
你在重复的事实
[Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
[RegularExpression("^[0-9]*$", ErrorMessageResourceType =typeof(DCC.RegistrationVMLiterals),ErrorMessageResourceName ="MustBeNumber")]
在此上下文中不是重复。
重复会是这样的:
public void DoSomething()
{
string myString = "ABC";
Print(myString);
Do something...
}
public void DoSomething1()
{
string myString = "ABC";
Print(myString);
Do something different...
}
对此的 DRY 响应是
public void DoSomething()
{
Print(getString());
Do something...
}
public void DoSomething1()
{
Print(getString());
Do something different...
}
public string getString()
{
return "ABC";
}
这是我的代码
[Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
[RegularExpression("^[0-9]*$", ErrorMessageResourceType =typeof(DCC.RegistrationVMLiterals),ErrorMessageResourceName ="MustBeNumber")]
[Display(Name = "BeneficiaryNo")]
public long BeneficiaryNo { get; set; }
[Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
[RegularExpression("^[a-zA-z]*$",ErrorMessage ="must only be letters")]
[Display(Name = "FullName")]
public string FullName { get; set; }
[Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
[Display(Name = "GenderID")]
public int GenderID { get; set; }`
试试这个,还没有测试过,但应该可以:
[AttributeUsage(AttributeTargets.Class)]
public class AggregatedRequiredAttribute: ValidationAttribute
{
private readonly string[] _propertiesToValidate;
private readonly string message = Resources.ValRequired;
public AggregatedRequiredAttribute(params string[] propertiesToValidate)
{
if (propertiesToValidate == null || !propertiesToValidate.Any()) throw new ArgumentException(nameof(propertiesToValidate));
_propertiesToValidate = propertiesToValidate;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (!validationContext.ObjectType.GetMember(validationContext.MemberName).Any())
throw new InvalidOperationException("Current type does not contain such property.");
if (!_propertiesToValidate.Contains(validationContext.MemberName))
return ValidationResult.Success;
var defaultRequired = new RequiredAttribute() {ErrorMessage = message};
return defaultRequired.IsValid(value) ? ValidationResult.Success : new ValidationResult(message);
}
}
然后你可以像这样使用它(来自默认 MVC 模板的 ViewModel):
[AggregatedRequired("Email","Password")]
public class RegisterViewModel
{
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
注意,我只使用了一次错误消息字符串,您也可以在错误消息中使用一些字母并将其动态替换为正在验证的 属性 的实际名称。
更新
我不确定第一个 if
语句,你应该测试一下。
更新 2
另外我想我用错了IsValid
方法,但思路本身很清楚。
我认为你误解了这个概念或 DRY。
你在重复的事实
[Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
[RegularExpression("^[0-9]*$", ErrorMessageResourceType =typeof(DCC.RegistrationVMLiterals),ErrorMessageResourceName ="MustBeNumber")]
在此上下文中不是重复。
重复会是这样的:
public void DoSomething()
{
string myString = "ABC";
Print(myString);
Do something...
}
public void DoSomething1()
{
string myString = "ABC";
Print(myString);
Do something different...
}
对此的 DRY 响应是
public void DoSomething()
{
Print(getString());
Do something...
}
public void DoSomething1()
{
Print(getString());
Do something different...
}
public string getString()
{
return "ABC";
}