Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding ValidationContext in DataAnnotations

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?

like image 288
UserControl Avatar asked Nov 30 '10 20:11

UserControl


People also ask

What is ValidationContext?

This class describes the type or member on which validation is performed. It also enables custom validation to be added through any service that implements the IServiceProvider interface.

What is property validation attribute?

Validates that a property value matches a specified regular expression. Built-in. Remote. Performs a remote validation: you call an action method on the server to validate inputs on the client.

What is the use of using system ComponentModel DataAnnotations?

Data annotations (available as part of the System. ComponentModel. DataAnnotations namespace) are attributes that can be applied to classes or class members to specify the relationship between classes, describe how the data is to be displayed in the UI, and specify validation rules.


Video Answer


1 Answers

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.

like image 112
Cylon Cat Avatar answered Oct 04 '22 11:10

Cylon Cat