简体   繁体   中英

ASP MVC: Custom Validation Attribute

I'm trying to write my own Custom Validation attribute but I'm having some problems.

The attribute I'm trying to write is that when a user logs in, the password will be compared against the confirmation password.

namespace Data.Attributes
{
public class ComparePassword : ValidationAttribute
{
    public string PasswordToCompareWith { get; set; }

    public override bool IsValid(object value)
    {
        if (PasswordToCompareWith == (string)value)
        {
            return true;
        }
       return false;
    }
}

Now my problem is when i'm trying to set the attribute like this in the model file:

 [Required]
    [ComparePassword(PasswordToCompareWith=ConfirmPassword)]
    public string Password { get; set; }


    [Required]
    public string ConfirmPassword { get; set; }
   }

I get the following error:

Error 1 An object reference is required for the non-static field, method, or property 'Project.Data.Models.GebruikerRegistreerModel.ConfirmPassword.get'

It seems that VS is not accepting the confirmpassword in the PasswordToCompareWith=ConfirmPassword part.

What am I doing wrong?

According to this link http://devtrends.co.uk/blog/the-complete-guide-to-validation-in-asp.net-mvc-3-part-1 there is an special validation attribute now in MVC3:

public class RegisterModel
{
    // skipped

    [Required]
    [ValidatePasswordLength]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }                       

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation do not match.")]
    public string ConfirmPassword { get; set; }
}

CompareAttribute is a new, very useful validator that is not actually part of System.ComponentModel.DataAnnotations, but has been added to the System.Web.Mvc DLL by the team. Whilst not particularly well named (the only comparison it makes is to check for equality, so perhaps EqualTo would be more obvious), it is easy to see from the usage that this validator checks that the value of one property equals the value of another property. You can see from the code, that the attribute takes in a string property which is the name of the other property that you are comparing. The classic usage of this type of validator is what we are using it for here: password confirmation.

Sorry to disappoint you but handling such a simple case like yours using Data Annotations could be a pain. You may take a look at this post .

I don't know why this is made out to be such a big deal, just do this:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
public class ComparePassword: ValidationAttribute
{
    public ComparePassword() 
        : base("Passwords must match.") { }

    protected override ValidationResult IsValid (object value, ValidationContext validationContext)
    {
        if (value == null) return new ValidationResult("A password is required.");

        // Make sure you change YourRegistrationModel to whatever  the actual name is
        if ((validationContext.ObjectType.Name != "YourRegistrationModel") 
             return new ValidationResult("This attribute is being used incorrectly.");
        if (((YourRegistrationModel)validationContext.ObjectInstance).ConfirmPassword != value.ToString())
            return new ValidationResult("Passwords must match.");

        return ValidationResult.Success;
    }
}

Now all you need to do is add [ComparePassword] to your password property, nothing to pass... simple and fairly clean

FoolProof http://foolproof.codeplex.com/ seems to be the best solution.

public class SignUpViewModel
{
    [Required]
    public string Password { get; set; }

    [EqualTo("Password", ErrorMessage="Passwords do not match.")]
    public string RetypePassword { get; set; }
}

It is better than suggested PropertiesMustMatchAttribute as it adds the validation error for the "RetypePassword' instead of the global model level as PropertiesMustMatchAttribute does.

you need a STATIC method in your case: EXAMPLE:

        public static ValidationResult ValidateFrequency( double frequency, ValidationContext context )
    {
        if( context == null )
        {
            return ( ValidationResult.Success );
        }
  }

just as an example:

 using System;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.Globalization;
 using System.Web.Mvc;
 using System.Web.Security;

 namespace GDNET.Web.Mvc.Validation
 {
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class ValidatePasswordLengthAttribute : ValidationAttribute, IClientValidatable
{
    private const string defaultErrorMessage = "'{0}' must be at least {1} characters long.";
    private readonly int minRequiredPasswordLength = Membership.Provider.MinRequiredPasswordLength;

    public ValidatePasswordLengthAttribute()
        : base(defaultErrorMessage)
    {
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, minRequiredPasswordLength);
    }

    public override bool IsValid(object value)
    {
        string valueAsString = value as string;
        return (valueAsString != null && valueAsString.Length >= minRequiredPasswordLength);
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        return new[]
        {
            new ModelClientValidationStringLengthRule(FormatErrorMessage(metadata.GetDisplayName()), minRequiredPasswordLength, int.MaxValue)
        };
    }
}
  }

source: https://code.google.com/p/gdnetprojects/source/browse/trunk/Experiments/Common/GDNET.Web.Mvc/Validation/ValidatePasswordLengthAttribute.cs?r=69

You can't pass a reference type to an attribute unless you do some rather lame reflection code.

In this situation, I would think creating a custom model binder would be a better idea and then checking the Password and ComparePassword at that point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM