Try this one, have not tested, but this should work:
[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);
}
}
Then u can use it like this (ViewModel from default MVC template):
[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; }
}
Notice, that i used error message string only once, also u can use some letter in error message and replace it dynamically to actual name of property being validated.
UPDATE
I am not sure about first if
statement, you should test it.
UPDATE 2
Also i guess i used wrong IsValid
method, but idea itself is clear.