24

I built a custom ValidationAttribute so I can validate unique email addresses in my system. However, I'd like to pass in a custom parameter somehow to add more logic to my validation.

public class UniqueEmailAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        //I need the original value here so I won't validate if it hasn't changed.
        return value != null && Validation.IsEmailUnique(value.ToString());
    }
}

4 Answers 4

62
+50

Like this?

public class StringLengthValidatorNullable : ValidationAttribute
{
    public int MinStringLength { get; set; }
    public int MaxStringLength { get; set; }

    public override bool IsValid(object value)
    {
        if (value == null)
        {
            return false;
        }
        var length = value.ToString().Length;

        if (length < MinStringLength || length >= MaxStringLength)
        {
            return false;
        }
        return true;
    }
}

Use:

[StringLengthValidatorNullable(MinStringLength = 1, MaxStringLength = 16)]
public string Name {get; set;}
Sign up to request clarification or add additional context in comments.

7 Comments

Kind of, but I can only pass constants that way, correct? I want to pass in the original value to compare to the value that is being validated.
Yes, only constants. I am not sure if I get your question. The validator can just validate the current value of a poperty, it does not know about any past values of a property.
That's specifically what I'm trying to do.
So you just can do a database call in your validator to compare the current value to the original value. You can also add a extra "orginal value" property to your model and compare to this value. You should be able do access other properties of the object via the ValidationContext.
The ValidationContext pointed me to the correct place. This link contains the method I used: anthonyvscode.com/2011/07/14/…
|
7

You could also pass parameters that are other properties in the same model.

Create a custom validation attribute:

public class SomeValidationAttribute : ValidationAttribute
{
    //A property to hold the name of the one you're going to use.
    public string OtherProperty { get; set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        //Get the value of the property using reflection.
        var otherProperty = validationContext.ObjectType.GetProperty(OtherProperty);
        var otherPropertyValue = (bool)otherProperty.GetValue(validationContext.ObjectInstance, null);

        if (value != null && otherPropertyValue)
        {
            return ValidationResult.Success;
        }

        return new ValidationResult("Invalid property message.");
    }
}

Then pass the name of the property you're going to use.

    public class RequestModel 
    {
        public bool SomeProperty { get; set; }

        [SomeValidation(OtherProperty = "SomeProperty")]
        public DateTime? StartDate { get; set; }
    }

1 Comment

I tried doing this and it did not pass anything like I thought it would.
1

Had a similar requirement where I had to pass along a value to a custom attribute.

The issue here is that Attribute decorations don't allow variables. You get compile time error:

An object reference is required for the non-static field, method, or property

Here is how I was able to do it:

In Controller

[FineGrainAuthorization]
public class SomeABCController : Controller
{
    public int SomeId { get { return 1; } }
}

In Attribute

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class FineGrainAuthorizationAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        ControllerBase callingController = filterContext.Controller;
        var someIdProperty = callingController.GetType().GetProperties().Where(t => t.Name.Equals("SomeId")).First();
        int someId = (int) someIdProperty.GetValue(callingController, null);
    }
}

Remember that the string inside .Name.Equals("SomeId") must case match the declaration public int SomeId

Comments

0

I would suggest something like @Oliver's answer (that's what I'd do, anyway), but then I noticed that you do not want to pass constants.

What about something like this, then?

public static class MyConfig
{
    public static int MinStringLength { get; set; }
    public static int MaxStringLength { get; set; }
    public static SomeObject otherConfigObject { get; set; }
}

And then access MyConfig.MinStringLength from validation? I'll agree that it isn't too pretty, though.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.