Introduction
In this second article, we will learn all validation forms in DataAnnotation. We will review Validator class with all its structure. The first part can be found on the following link.
DataAnnotation enables us to work with positive programming. In other words, it allows us anticipate exceptions for problems in our business classes or domain classes. It provides better performance. The negative programming version also exists.
- Positive - TryValidate.
- Negative - Validate.
On this link, you will get the information about Exceptions and Performance.
The examples class
The class for all examples will be a new version of the class created in part I.
- public class Customer
- {
- [Required(ErrorMessage = "{0} is mandatory")]
- [MaxLength(50, ErrorMessage = "The {0} can not have more than {1} characters")]
- public string Name { get; set; }
-
- [Range(typeof(DateTime), "01/01/2016", "01/01/2050",
- ErrorMessage = "Valid dates for the Property {0} between {1} and {2}")]
- public DateTime EntryDate { get; set; }
-
- public string Password { get; set; }
-
- [Compare("Customer.Password", ErrorMessage = "The fields Password and PasswordConfirmation should be equals")]
- public string PasswordConfirmation { get; set; }
-
- [Range(0, 150, ErrorMessage = "The Age should be between 0 and 150 years")]
- public int Age { get; set; }
- }
These are principal validation classes.
ValidationResult
ValidationResult is a container for class validation results. For more info, go
here.
ValidationResult has 2 properties
- ErrorMessages .- String readonly property with the information error description.
- MemberNames.- IEnumerable<string> readonly property with the property name on error.
We have written an extension method to print the validation errors.
- public static string ToDescErrorsString(this IEnumerable<ValidationResult> source, string mensajeColeccionVacia = null)
- {
- if (source == null) throw new ArgumentNullException(nameof(source), $"The property {nameof(source)}, doesn't has null value");
-
- StringBuilder resultado = new StringBuilder();
-
- if (source.Count() > 0)
- {
- resultado.AppendLine("There are validation errors:");
- source.ToList()
- .ForEach(
- s =>
- resultado.AppendFormat(" {0} --> {1}{2}", s.MemberNames.FirstOrDefault(), s.ErrorMessage,
- Environment.NewLine));
- }
- else
- resultado.AppendLine(mensajeColeccionVacia ?? string.Empty);
-
- return resultado.ToString();
- }
Validator class
This is the static helper class. The Validator class allows you to execute validation on objects, properties, and methods. You can get more information from this
link.
We can separate its methods in two groups, as we saw earlier.
POSITIVE PROGRAMMING (Returns bool value and we have a ICollection<ValidationResult> parameter)
The return property bool is a validation result.
The ICollection<ValidationResult> argument contains details of validation errors. If the validation doesn't have errors, this collection will be empty.
TryValidateObject
- public static bool TryValidateObject(object instance, ValidationContext validationContext, ICollection<ValidationResult> validationResults);
- public static bool TryValidateObject(object instance, ValidationContext validationContext, ICollection<ValidationResult> validationResults, bool validateAllProperties);
This method validates all objects. TryValidateObject has an overload with a bool argument validateAllProperties that is enabled in case when validation error continues with the validation of all properties.
Arguments
- Instance The instance of class to validate.
- ValidationContext The context that describes the object to validate.
- ValidationResults The collection of validation results descriptions.
- ValidateAllProperties Enabled continues to validate all properties.
Example
- public static void TryValidateObjectExample1()
- {
-
- var customer = new Customer
- {
- Name = string.Empty,
- EntryDate = DateTime.Today,
- Password = "AAAA",
- PasswordConfirmation = "BBBB",
- Age = -1
- };
-
- ValidationContext valContext = new ValidationContext(customer, null, null);
-
- var validationsResults = new List<ValidationResult>();
-
- bool correct = Validator.TryValidateObject(customer, valContext, validationsResults, true);
-
- Console.WriteLine(validationsResults.ToDescErrorsString("Without Errors !!!!"));
- Console.Read();
- }
In this example, we have done the second overload with true value (ValidateAllProperties).
Result
We have validated all customer properties.
If we change the last argument to false, it only validates the first property on error.
- public static void TryValidateObjectExample2()
- {
-
- var customer = new Customer
- {
- Name = string.Empty,
- EntryDate = DateTime.Today,
- Password = "AAAA",
- PasswordConfirmation = "BBBB",
- Age = -1
- };
-
- ValidationContext valContext = new ValidationContext(customer, null, null);
-
- var validationsResults = new List<ValidationResult>();
-
- bool correct = Validator.TryValidateObject(customer, valContext, validationsResults, false);
-
- Console.WriteLine(validationsResults.ToDescErrorsString("Without Errors !!!!"));
- Console.Read();
- }
Result
TryValidateProperty
- public static bool TryValidateProperty(object value, ValidationContext validationContext, ICollection<ValidationResult> validationResults);
It has only one overload. It has the same parameters as of TryValidateObject, but the first object parameter does match with one property to validate and the method, therefore, validates properties.
- public static void TryValidatePropertyExample()
- {
-
- var customer = new Customer
- {
- Name = string.Empty,
- EntryDate = DateTime.Today,
- Password = "AAAA",
- PasswordConfirmation = "BBBB",
- Age = -1
- };
-
- ValidationContext valContext = new ValidationContext(customer, null, null)
- {
- MemberName = "Age"
- };
-
- var validationsResults = new List<ValidationResult>();
-
- bool correct = Validator.TryValidateProperty(customer.Age, valContext, validationsResults);
-
- Console.WriteLine(validationsResults.ToDescErrorsString("Without Errors !!!!"));
- Console.Read();
- }
Note
When we instance the ValidationContext object, we give value to string property MemberName with the property name to validate.
The TryValidateProperty and the TryValidateObject are equal. The only change is the first parameter. The TryValidateProperty will have to call the property value.
Result
TryValidateValue
- public static bool TryValidateValue(object value, ValidationContext validationContext, ICollection<ValidationResult> validationResults, IEnumerable<ValidationAttribute> validationAttributes);
TryValidateValue validates a value through ValidationAttribute collection. This is practical to reuse our ValidationAttributes and for us to be disabused of the if terms.
- public static void TryValidateValueExample()
- {
-
- string myPwd = "33223";
-
- MinLengthAttribute minLengthAtribute = new MinLengthAttribute(8) { ErrorMessage = "{0} must have {1} caracters minimum" };
- RequiredAttribute requieredAttribute = new RequiredAttribute { ErrorMessage = "{0} is mandatory" };
- List<ValidationAttribute> atributes = new List<ValidationAttribute>() { minLengthAtribute, requieredAttribute };
-
- ValidationContext valContext = new ValidationContext(myPwd, null, null)
- {
- MemberName = "myPwd"
- };
-
- var validationsResults = new List<ValidationResult>();
-
- bool correct = Validator.TryValidateValue(myPwd, valContext, validationsResults, atributes);
-
- Console.WriteLine(validationsResults.ToDescErrorsString("Without Errors !!!!"));
- Console.Read();
- }
Note - We have created the attributes in code, because we will validate a value and we don’t have properties to mark in the class declaration.
Result
NEGATIVE PROGRAMMING (throw ValidationException and it hasn’t ICollection<ValidationResult argument )
These methods remove the word Try in your names. They are void methods. If the validation fails, it will throw a ValidationException.
They don’t have an ICollection<ValidationResult> argument. This information will have an inside exception and it isn’t a collection. But, it is a simple ValidationResult because if validation fails, it doesn’t verify the remaining properties.
- public static void ValidateObject(object instance, ValidationContext validationContext);
- public static void ValidateObject(object instance, ValidationContext validationContext, bool validateAllProperties);
- public static void ValidateProperty(object value, ValidationContext validationContext);
- public static void ValidateValue(object value, ValidationContext validationContext, IEnumerable<ValidationAttribute> validationAttributes);
Example
- public static void ValidateObjectExample()
- {
-
- var customer = new Customer
- {
- Name = string.Empty,
- EntryDate = DateTime.Today,
- Password = "AAAA",
- PasswordConfirmation = "BBBB",
- Age = -1
- };
-
- ValidationContext valContext = new ValidationContext(customer, null, null);
-
- try
- {
-
- Validator.ValidateObject(customer, valContext, true);
- }
- catch (ValidationException ex)
- {
-
- ValidationResult s = ex.ValidationResult;
-
- Console.WriteLine("There are validation errors:");
- Console.WriteLine(" {0,-20} --> {1}{2}", s.MemberNames.FirstOrDefault(), s.ErrorMessage,
- Environment.NewLine);
- }
-
-
- Console.Read();
- }
Result
The other methods are same as the ‘Try’ version.
Considerations and tests
Remember, we can use the extension method of Chapter I.
You have the source code to test the examples.