24

I want to utilize Validator.TryValidateValue() but don't understand the mechanics. Say, i have the following:

public class User {
    [Required(AllowEmptyStrings = false)]
    [StringLength(6)]
    public string Name { get; set; }
}

and the method:

public void CreateUser(string name) {...}

My validation code is:

ValidationAttribute[] attrs = bit of reflection here to populate from User class
var ctx = new ValidationContext(name, null, null);
var errors = new List<ValidationResult>();
bool valid = Validator.TryValidateValue(name, ctx, errors, attrs);

It works fine until value of name is null. I'm getting ArgumentNullException when instantiating ValidationContext and don't understand why. TryValidateValue() also demands non-null context. I have a value and a list of attributes to validate against. What is that ValidationContext for?

2
  • Not having fooled with this before it looks to me that you should be passing the object type into the ValidationContext, not the property ...so passing in an instance of User which is not null. Commented Nov 30, 2010 at 21:13
  • If you want to customize the attribute of DataAnnotation, you can go to my post Beside, you also customize the validator. Commented Nov 30, 2010 at 22:29

1 Answer 1

19
+50

The only thing that's wrong about your code is the instance object for your validation context. The instance does not need to be the value that's being validated. For Validator.ValidateProperty, yes, it does need to be the object that owns the property, but for Validator.ValidateValue, "this" is sufficient.

I wrote a validation helper class to do the setup; this lets me pass in arbitrary values from anywhere.

public class ValidationHelper
{
    private List<ValidationResult> m_validationResults = new List<ValidationResult>();
    private List<ValidationAttribute> m_validationAttributes = new List<ValidationAttribute>();

    public Tuple<bool, List<string>> ValidateDOB(DateTime? dob)
    {
        m_validationAttributes.Add(new CustomValidationAttribute(typeof(DateOfBirthValidator), "ValidateDateOfBirth"));
        bool result = Validator.TryValidateValue(dob, 
                             new ValidationContext(this, null, null), 
                             m_validationResults, 
                             m_validationAttributes);
        if (result)
        {
            return Tuple.Create(true, new List<string>());
        }
        List<string> errors = m_validationResults.Select(vr => vr.ErrorMessage).ToList();
        return Tuple.Create(false, errors);
    }
}

If you are validating properties that have the validation attributes on the property, it's a lot easier:

internal void Validate(T value)
{
    if (!m_Initializing && TrackChanges && !Entity.IsImmutable)
    {
        Validator.ValidateProperty(value, new ValidationContext(Entity, null, null) { MemberName = PropertyName ?? ModelName });
    }
}

"Entity" is a property of the current class that references the object that I want to validate. This lets me validate properties on other objects. If you're already inside the objct, "this" will again be sufficient.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, my colleague also suggested me to pass anything non-null to ValidationContext and it worked. But i still don't understand why TryValidateValue() demands ValidationContext. Bad design? Only the creators know but i didn't hope to see their answer here so +50 to you.
Thank you! The object instance makes sense for validating objects and properties, but much less for validating values, and it's the same ValidationContext class in all cases. You might get some insight into designer intent by stepping through the source code in the Visual Studio debugger. See referencesource.microsoft.com for instructions on downloading source and setting up Visual Studio to debug into .NET framework classes.
@UserControl Here's a blog post explaining ValidationContext by the one of the creators: jeffhandley.com/archive/2010/10/25/…
Why is all of this validation code even required when you have the validation attributes on the model? If you post to the server and return the view based on ModelState.IsValid the validation errors will show up in a validation summary.
This is for custom validators, beyond what the framework provides. It also allows validation to be called directly from any code if the need arises.

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.