4

I'm attempting to use DataAnnotation attribute validation outside of an ASP.net MVC application. Ideally I'd like to take any model class in my console application and decorate it as follows:

private class MyExample
{
    [Required]
    public string RequiredFieldTest { get; set; }

    [StringLength(100)]
    public int StringLengthFieldTest { get; set; }

    [Range(1, 100)]
    public int RangeFieldTest { get; set; }

    [DataType(DataType.Text)]
    public object DataTypeFieldTest { get; set; }

    [MaxLength(10)]
    public string MaxLengthFieldTest { get; set; }
}

Then (pseudo) do something like this:

var item = new MyExample(); // not setting any properties, should fail validation
var isValid = item.Validate();

I found this code in a sample online:

var item = new MyExample(); // not setting any properties, should fail validation

var context = new ValidationContext(item, serviceProvider: null, items: null);
var errorResults = new List<ValidationResult>();

// carry out validation.
var isValid = Validator.TryValidateObject(item, context, errorResults);

// isValid will be FALSE

Which gives me "isValid = false" BUT it only seems to uphold the Required field and ignores the others.

The following code returns isValid = true when I expect it to return false:

var item = new MyExample() {
    RequiredFieldTest = "example text"
};

var context = new ValidationContext(item, serviceProvider: null, items: null);
var errorResults = new List<ValidationResult>();

// carry out validation.
var isValid = Validator.TryValidateObject(item, context, errorResults);

// isValid will be TRUE - not expected behavior

All other validation attempts using attributes (string length, range, max length, datatype etc) all pass as valid.

Has anyone seen this behaviour before or know why it's happening?

1 Answer 1

8

TryValidateObject by default validates only the required attribute. You can pass it a fourth parameter validateAllProperties = true, to validate the other attributes.

if (!Validator.TryValidateObject(item, context, errorResults, true)) {
    //invalid
}
Sign up to request clarification or add additional context in comments.

5 Comments

This is great! Works perfectly for all except the [DataType] attribute. If I set DataType to be DataType.Email or something for testing, it still returns its valid - even if I just set a random data object or string that's definitely not an email. Any ideas why this one isn't being picked up?
You seem to keep stumbling on the most unintuitive aspects of the framework. DataType despite inheriting from ValidationAttribute doesn't perform validation, and is used for display purposes, it overrides IsValid to always return true. Check DataTypeAttribute.cs. Instead use a custom validation, or the EmailAddress attribute.
Why does TryValidateObject require item if context already references it? Struggling to understand the purpose of the context.
That's an interesting question, I've always meant to look into it, so thanks for the reminder! For the first question, according to the ValidationContext class, "during validation, especially property-level validation, the object instance might be in an indeterminate state... consume this instance with caution". Check GetPropertyValues() in Validator.cs.
For the second question, the ValidationContext does as the name says, it provides contextual information of the validation taking place so other classes that actually perform the validation can access this information (information like MemberName or DisplayName of the property being validated). To see an example of how the context is being used and how this information is accessed, check ValidationAttribute.cs's IsValid() method.

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.