More Data Annotations

Here are more stuff that I discovered that we can do with Data Annotations.

Re-use Validation in Business Components

You will be pleased to know that the validations that you have coded for your data annotations can be easily reused in business components and they don't necessary need to be dependent on UI components. To activate them, simply use the following code snippet:

// Activate Data Annotation validation.
var context = new ValidationContext(leave);
var validationErrors = new List<ValidationResult>();
Validator.TryValidateObject(leave, context, validationErrors, true);

if (validationErrors.Count > 0)
    throw new ApplicationException(validationErrors[0].ErrorMessage);

In the above code snippet, leave is an instance of the Leave Entity. The call to TryValidateObject will return a list of ValidationResults if there are any validation errors. The first error in the list is thrown as an exception to the calling function.

Writing Custom Validation Attributes

Although we can use the RegularExpression validation attribute to satisfy most of the non-standard validation requirements, there will always be scenarios where we will need to build our own custom validation attribute.

For example, what if we have a requirement to ensure that the StartDate is not greater than the EndDate? It would be impossible to use the standard out-of-the-box validation attributes to do it. Instead, we can write a custom validation attribute that targets the Entity class instead.

[AttributeUsage(AttributeTargets.Class)]
public class DateRangeConstraintAttribute : ValidationAttribute
{
    public DateRangeConstraintAttribute() : base () { }

    public DateRangeConstraintAttribute(string errorMessage)
        : base(errorMessage) { }

    public override bool IsValid(object value)
    {
        if (value == null || value.GetType() != typeof(Leave))
            return true;

        var leave = value as Leave;

        return !(leave.StartDate > leave.EndDate);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value == null || value.GetType() != typeof(Leave))
            return ValidationResult.Success;

        if (!IsValid(value))
        {
            var result = new ValidationResult("Start date cannot be greater than End date.",
                new List<string>() { "StartDate", "EndDate" } );

            return result;
        }

        return base.IsValid(value, validationContext);
    }

}

We can then apply the custom validation attribute to our Entity class like this:

[DataContract]
[DateRangeConstraint]
public partial class Leave

Our validation will be invoke when data annotations are being invoke (either automatically in UI or manually in business components).

Things To Know...

There are some other things that I discovered about Data Annotations.

All validations are executed and this prevents the code from stopping on first error encountered. If your validation needs to be executed step-by-step, you may need to rethink your strategy.

The order of validation is unpredictable and difficult to control. Most of the time, it is depending on which attribute was declared first.

Hope you find this information useful.

No comments:

Post a Comment

Popular Post