Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC - Pass model value to data annotation parameter

I want to pass a value from one of my properties in my model to my data annotation to validate my password property, but I have no idea how I can achieve this. When I am doing this at this way I get the following error:

an attribute argument must be a constant expression typeof expression or array

My model:

public class LoginModel
{
    public string Voornaam { get; set; }
    public string Achternaam { get; set; }
    public string Gebruikersnaam { get; set; }

    [Password(AttributeVoornaam = this.Voornaam, AttributeAchternaam = this.Achternaam, AttributeGebruikersnaam = this.Gebruikersnaam)]
    public string Wachtwoord { get; set; }
}

And in my data annotation I am doing this:

public class PasswordAttribute : ValidationAttribute
{
    public string AttributeVoornaam { get; set; }
    public string AttributeAchternaam { get; set; }
    public string AttributeGebruikersnaam { get; set; }

    public override bool IsValid(object value)
    {
        string strValue = value.ToString();

        if (strValue.Contains(AttributeVoornaam.ToLower()) || strValue.Contains(AttributeAchternaam.ToLower()) ||
               strValue.Contains(AttributeGebruikersnaam.ToLower()))
        {
            ErrorMessage = "Uw wachtwoord mag niet uw voornaam, achternaam of gebruikersnaam bevatten.";
            return false;
        }
        else
        {
            return true;
        }
    }
}
like image 617
Jamie Avatar asked Dec 06 '22 03:12

Jamie


2 Answers

You can't pass variable values (values that are not evaluated at compile-time) into attributes. They have to be literal values or constant values.

What you can pass into attributes, though, are the names of the properties of your model that you want to evaluate at run-time, and then have your IsValid method evaluate these values at run-time by accessing the ValidationContext in the override that returns a ValidationResult of ValidationAttribute.

Or, if you are always evaluating these same properties, then you can just grab the reference to your model, and use that directly:

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
    LoginModel loginModel = (LoginModel)validationContext.ObjectInstance;

    string strValue = value.ToString();

    if (strValue.Contains(loginModel.Voornaam.ToLower()) || 
        strValue.Contains(loginModel.Achternaam.ToLower()) ||             
        strValue.Contains(loginModel.Gebruikersnaam.ToLower()))
    {
        ErrorMessage = "Uw wachtwoord mag niet uw voornaam, achternaam of gebruikersnaam bevatten.";
        return false;
    }
    else
    {
        return true;
    }
}
like image 94
Jerad Rose Avatar answered Jan 01 '23 08:01

Jerad Rose


It's not possible, because the attributes, including their data, are placed into the metadata of the assembly at compile-time. See Attribute parameter types on MSDN.

Instead you can pass a name of the dependent property as a string. I will show you a sample with one property and you will add others the same way:

public class PasswordAttribute : ValidationAttribute
{
    public PasswordAttribute(string voornaamPropertyName)
    {
        if(string.IsNullOrEmpty(voornaamPropertyName))
            throw new ArgumentNullException("voornaamPropertyName");

        VoornaamPropertyName = voornaamPropertyName;
    }

    public string VoornaamPropertyName { get; set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        PropertyInfo voornaamPropertyInfo = validationContext.ObjectType.GetProperty(VoornaamPropertyName);
        if (voornaamPropertyInfo == null)
        {
            return new ValidationResult(String.Format(CultureInfo.CurrentCulture, "Could not find a property named {0}", VoornaamPropertyName));
        }

        var voornaamProperty = voornaamPropertyInfo.GetValue(validationContext.ObjectInstance); // here you have the value of the property

       ...
    }
}

Then

[Password("Voornaam")]
public string Wachtwoord { get; set; }
like image 31
Zabavsky Avatar answered Jan 01 '23 07:01

Zabavsky