Search code examples
c#asp.net-web-apivalidationattribute

Is it possible to access properties from a different model in a ValidationAttribute


I have a web api with some nested models that are being bound like so:

public class Class1 {
  //This data is needed in Class2 and Class3 validation
  public bool ImportantInformation {get; set;}
  public Class2 A {get; set;}
  public Class3 B {get; set;}
}

public class Class2 {
  [ConditionallyValidatedAttribute]
  public string X {get; set;}
}

public class Class3 {
  [ConditionallyValidatedAttribute]
  public string Y {get; set;}
}

ConditionallyValidatedAttribute looks like this:

public sealed class ConditionallyValidatedAttribute : ValidationAttribute {
  protected override ValidationResult IsValid(object value, ValidationContext vc) {
    bool importantInformation = //How do I get Class1.ImportantInformation?
    if(importantImformation && value == null) {
      return new ValidationResult($"{vc.MemberName} is invalid");
    }
    return ValidationResult.Success;
  }
}

My question is is there some way to inject ImportantInformation into ConditionallyValidatedAttribute as needed?


Solution

  • As far as I know - there is no way to do that, as instance A itself is not aware that it belongs to parent.
    But there is another way. Instead of applying ConditionallyValidatedAttribute to property X or Y, you can apply it to entire A or B inside of your parent. Doing that you can have access to the whole A and ImportantInformation inside of your IsValid method. Something like that:

    public class Class1 
    {
        public bool ImportantInformation {get; set;}
        [ConditionallyValidatedAttribute] //-->Validation Attribute here
        public Class2 A {get; set;}
        public Class3 B {get; set;}
    }
    
    public class Class2 
    {
        public string X {get; set;}
    }  
    
    public sealed class ConditionallyValidatedAttribute : ValidationAttribute 
    {
        protected override ValidationResult IsValid(object value, ValidationContext vc) 
        {
            var importantInformation = bool.Parse(vc.ObjectType.GetProperty("ImportantInformation")?.GetValue(vc.ObjectInstance)?.ToString() ?? "false");
            if (importantInformation && (!(value is Class2) || string.IsNullOrEmpty(((Class2)value).X)))
            {
                return new ValidationResult($"{vc.MemberName} is invalid");
            }
    
            return ValidationResult.Success;
        }
    }