0

I have a model in web api which has 5 properties.

[CheckAtleastNProperties2(ErrorMessage = "Please provide atleast one property")]
public class Class1
{

    [RequiredIfCustom("Provide either prop1 and prop2 or prop3, prop4 and prop5.", "prop2")]
    public string prop1 { get; set; }
    [RequiredIfCustom("Provide either prop1 and prop2 or prop3, prop4 and prop5.", "prop1")]
    public int prop2 { get; set; }
    [RequiredIfCustom("Provide either prop1 and prop2 or prop3, prop4 and prop5.", "prop4", "prop5")]
    public string prop3 { get; set; }
    [RequiredIfCustom("Provide either prop1 and prop2 or prop3, prop4 and prop5.", "prop3", "prop5")]
    public string prop4 { get; set; }
    [RequiredIfCustom("Provide either prop1 and prop2 or prop3, prop4 and prop5.", "prop3", "prop4")]
    public string prop5 { get; set; }
}

I have created two custom attributes CheckAtleastNProperties2 for class and RequiredIfCustom for properties, now what I want is to check if user has provided at least one property and then check property validation RequiredIfCustom() but instead of checking CheckAtleastNProperties2 first, it is checking RequiredIfCustom first always, is it possible to check or force class level validation attribute to call first instead of property level validation attribute first?

here's the implementation of CheckAtleastNProperties2, it checks whether user has provided value for at least one property or not:

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class CheckAtleastNProperties2 : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var properties = validationContext.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
        if (properties.Where(x => x.GetValue(value, null) != null && x.PropertyType.IsValueType && !x.GetValue(value).Equals(Activator.CreateInstance(x.PropertyType))).Count() != 0)
        {
            return ValidationResult.Success;
        }
        else
        {
            //ErrorMessage = "Provide either Accountnumber and InstitutionID or Fname, Lname and Last4DigitSSN.";
            return new ValidationResult.Success;
        }

    }
}

here's the implementation of RequiredIfCustomAttribute, it checks if user provides value for prop1, then it should provide value for prop2 and so on:

[AttributeUsage(AttributeTargets.Property)]
public class RequiredIfCustomAttribute : ValidationAttribute
{
    private string[] _properties { get; set; }
    private string _errorMessage { get; set; }
    public RequiredIfCustomAttribute(string errorMessage = null, params string[] properties)
    {
        _properties = properties;
        _errorMessage = errorMessage;
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        //logic for conditional check 
        return ValidationResult.Success;
    }
}

my question is, it always calls RequiredIfCustom first before CheckAtleastNProperties2,I hope it is clear now.

ecstatic
  • 114
  • 1
  • 9
  • I don´t get your question. What does "check property validation RequiredIfCustom()" mean? Could you elaborate what exactly your validation should do? – MakePeaceGreatAgain Nov 13 '19 at 14:31
  • Have not used core, but the MVC way used to be IValidatable interface: https://weblogs.asp.net/scottgu/class-level-model-validation-with-ef-code-first-and-asp-net-mvc-3 – Steve Greene Nov 13 '19 at 15:10
  • @HimBromBeere, these are validation attributes. – ecstatic Nov 14 '19 at 05:54
  • What's the specific implementation of custom validation properties? Based on the custom attribute names provided only, we are unable to provide effective suggestions or workarounds to your issue. – Xueli Chen Nov 14 '19 at 06:09
  • @XueliChen updated question. – ecstatic Nov 14 '19 at 06:35

1 Answers1

0

You need to implement IValidatableObject. Put validation checks in Validate method. return list of errors in the end.

public class Class1 : IValidatableObject
{
    public string prop1 { get; set; }
    public int? prop2 { get; set; }
    public string prop3 { get; set; }
    public string prop24 { get; set; }
    public string prop5 { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<ValidationResult> errors = new List<ValidationResult>();
        if (string.IsNullOrWhitespace(prop1) && prop2.IsNull && string.IsNullOrWhitespace(prop3) && string.IsNullOrWhitespace(prop4) && string.IsNullOrWhitespace(prop5) &&)
        {
             errors.Add(new ValidationResult($"Please provide at least one property.", new List<string> { }));
        }
        return errors;
    }
}

see Microsoft documentation https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-3.0#ivalidatableobject

see original answer ASP.NET Core Conditional Validation for controls.

Arjun Vachhani
  • 1,761
  • 3
  • 21
  • 44