// [RequiredIf("SomeOtherProperty")] -- required if the other property is true // [RequiredIf("SomeIntProperty", OtherPropertyValue = 42)] -- required if the other property is 42 public class RequiredIfAttribute : ValidationAttribute, IClientValidatable { public string OtherPropertyName { get; } public object OtherPropertyValue { get; set; } public RequiredIfAttribute(string otherPropertyName) { OtherPropertyName = otherPropertyName; } public override bool RequiresValidationContext => true; protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var prop = validationContext.ObjectType.GetProperty(OtherPropertyName); if (prop == null) throw new InvalidOperationException($"Could not find property {OtherPropertyName} on type {validationContext.ObjectType}."); var otherValue = prop.GetValue(validationContext.ObjectInstance); bool isRequired; if (otherValue is true) isRequired = true; else { isRequired = otherValue?.Equals(OtherPropertyValue) ?? false; } if (isRequired) { if (value == null || (value is string s && s.Trim() == "")) { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } } return ValidationResult.Success; } public override string FormatErrorMessage(string name) { return string.Format(ErrorMessageString, name, OtherPropertyName); } // adds a data-val-requiredif attribute data-val-requireif-other="OtherPropertyName" data-val-requiredif-value="42" public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule() { ErrorMessage = FormatErrorMessage(metadata.DisplayName), ValidationType = "requiredif", ValidationParameters = { { "other", OtherPropertyName } } }; if (OtherPropertyValue != null) { rule.ValidationParameters["value"] = OtherPropertyValue.ToString(); } yield return rule; } }