James Wilkinson
James Wilkinson

Reputation: 205

Retrieving the value of a condition within a custom conditional ValidationAttribute

I've got a custom MVC validation attribute called [DateOfBirth] - it's used in the model like this:

[DateOfBirth("DOBMinimumAgeValidation", 18, 100, ErrorMessage = "Please enter a valid date of birth")]
public DateTime? DateBirth { get; set; }

public Boolean DOBMinimumAgeValidation { get; set; }

"18" is the minimum age and "100" is the maximum age.

The idea is, I can pass in the "DOBMinimumAgeValidation" property as a parameter and if this parameter is true, it will override the "minimum date of birth" check.

So, this is my code for the attribute:

public class DateOfBirthAttribute : ValidationAttribute, IClientValidatable
{
    public DateOfBirthAttribute(string conditionalProperty, int minAge, int maxAge)
    {
        _other = conditionalProperty;
        MinAge = minAge;
        MaxAge = maxAge;
    }

    public int MinAge { get; private set; }
    public int? MaxAge { get; private set; }
    private string _other { get; set; }

[...]

The idea is, I want to get the value of "_other" within the GetClientValidationRules method so that I can override it and set "MinAge" to 0 if the value is true, like this:

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
    ModelMetadata metadata,
    ControllerContext context)
{
    //yield return new ModelClientValidationRule
    var rule = new ModelClientValidationRule
    {
        ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "dateofbirth"
    };

    if(_other.GetTheValueSomehow() == true)
        MinAge = 0;

    rule.ValidationParameters.Add("minimumage", MinAge);
    rule.ValidationParameters.Add("maximumage", MaxAge.GetValueOrDefault(999));

    yield return rule;
}

But, I can't pass the "ValidationContext" object to it as this can only be inherited from the ValidationResult type - so my question is, how would I get the boolean value of "_other"?

Upvotes: 3

Views: 288

Answers (1)

Viktor Bahtev
Viktor Bahtev

Reputation: 4908

I don't know if this this helps but after I looked at ModelMetadata metadata and ControllerContext context I found that the actual model which will be validated can be accessed through metaData.Container. The rest is simple c# statements and reflection. Get the model, check if it has boolean property with name _other and if such property exists check if its value is true:

var model = metadata.Container;
if (model != null)
{
    var property = model.GetType().GetProperty(_other, typeof(bool));

    if (property != null && (bool)property.GetValue(model))
    {
        MinAge = 0;
    }                
}

Upvotes: 1

Related Questions