ONE of the annoying aspects with traditional ASP.Net development was that validation logic which seemed well fitted to be in the mid-tier would often be replicated into the UI-tier. One does this to provide instant feedback to application users; increasing user experience and the application’s usability. The drawback is of course the doubling up of this logic. No only that, but quite often you would have the duplication of logic across different languages; for example mid-tier validation would be coded in C# whereas UI-tier validation would be coded in Javascript – causing a myriad of headaches with code maintenance.

So along comes WCF RIA Services and its validation framework. In this article I’ll provide details on how WCF RIA Services approachs validation; and how it has been designed to resolve issues of its predecessors..

There are two main categories of Validation within RIA Services:

  1. Client side validation
  2. Server side validation


Client side Validation

So we all know the benefits of Client-side validation.. Instant data validation without the need for any service or database calls. Because it’s extremely call-efficient it provides great performance gains in the system. But with one limitation – the client side must have all the necessary data for it to complete its validation logic. Which kind of makes sense when you think about it.. without having all its parameters to validate with it won’t be able to complete successfully.

Server side Validation

This is where it gets interesting. If your validation requires data not available on the Client, then server side validation is the definitely way to go. You can achieve server side validation by exposing Invoke methods in your Domain Service. The Client can explicitly make the domain service call on-demand. This fits into the traditional way of validation; and in many cases works absolutely fine. Of course, with RIA services you can go one step further.. using Custom Validation.

There are two styles of Validation available:

  1. Declarative validation
  2. Custom validation


Declarative Validation

Declarative Validation is the simplest of the two forms of Validation. It provides simple and easy to maintain validation logic triggered on the Client. This is achieved by using Metadata Annotations with your Entity object Properties that require the validation. These annotations are part of the System.ComponentModel.DataAnnotations namespace and are derivative classes of ValidationAttribute. There’s only a small list of these but they should suffice for simple validation logic:

  • StringLength
  • Required
  • Range
  • RegularExpression


Below is an example of how to use declarative validation in an Entity class called Person.

using System.ComponentModel.DataAnnotations;

    public class Person
    {
        [Key]
        public int ID { get; set; }

        [Required]
        [StringLength(50, ErrorMessage="Forename cannot exceed 50 characters.")]
        public string Forename { get; set; }

        [Required]
        [StringLength(50, ErrorMessage="Surname cannot exceed 50 characters.")]
        public string Surname { get; set; }

        [Range(1, 150, ErrorMessage="Age must be between 1 and 150.")]
        public int Age { get; set; }

        public int StreetNumber { get; set; }
        public string StreetName { get; set; }

        public int PostCode { get; set; }
    }

Custom Validation

Custom Validation can be used for both Client and Server side validation. Depending on your logic you will need to split your Client and Server side validation code into different classes. The basic principle should be:

  • If the logic is simple enough to be covered by the Declarative Validation method – then use the available Declarative Validation attributes.
  • However, if the logic is slightly more complicated + all validation parameters are available on the Client – then follow the Client Side Custom Validation method
  • Lastly, if the logic is slightly more complicated + not all validation parameters are available on the Client – then follow the Server Side Custom Validation method.


Custom Validation – Client side

With Client side Custom Validation you will need to be defined in a *.shared file to ensure the code is generated on the Client. Along with this, your class needs to be declared as public static partial, and your validation methods declared as public static returning a ValidationResult object.

As an example, say you wanted to ensure that the StreetNumber property has a positive non-zero value. You can probably use the RANGE attribute to ensure it has a minimum value of 1.  But there really isn’t a maximum figure that you can put in. So by using declaring Custom Validation for the StreetNumber, you can simply check that it is not less than zero.

Below is the validation class that will be generated for the Client:

  • File must be in the format of a shared file, eg: PersonClientValidation.shared.cs
  • Class declared as public static partial class …
  • Validation method declared as public static ValidationResult
  • Return ValidationResult.Success if validation passes
  • Return a new ValidationResult object if validation fails
using System.ComponentModel.DataAnnotations;

    public static partial class PersonClientValidation
    {
        public static ValidationResult StreetNumberPositive(int streetNumber, ValidationContext validationContext)
        {
            if (streetNumber< 0)
            {
                return new ValidationResult("Street Number must be positive and non-zero.");
            }
            return ValidationResult.Success;
        }
    }

Once that is done, we’re ready to add the CustomValidation attribute to the StreetNumber property, and point it to the StreetNumberPositive(…) method. Just put this attribute above the Property, and that’s it! When the user enters a StreetNumber < 0 the application will automatically throw the validation error and display the message to the user.

using System.ComponentModel.DataAnnotations;

    public class Person
    {
        [Key]
        public int ID { get; set; }

        //... other properties hidden ... //

        [CustomValidation(typeof(PersonClientValidation), "StreetNumberPositive")]
        public int StreetNumber { get; set; }

        public string StreetName { get; set; }
    }

Custom Validation – Server side

With Server side Custom Validation the opportunities are limitless. Because the validation is processed on the Server you can utilise all your mid-tier code for data retrieval or additional processing while performing the required validation logic. One main reason we need to split the Server side Custom Validation from the Client side Custom Validation code is because the Server side logic may contain references to mid-tier code that is inaccessible by the Client. If we placed it in the same *.shared.cs class there will be a compilation error when creating mid-tier objects and service classes.

So create another class that we will use for the Server side validation of the Person class:

  • This is just a mid-tier class, so the naming format is just a basic class file. ie don’t use *.shared.cs
  • Class declared as public static class
  • Validation method declared as public static ValidationResult (obj propertyValue, ValidationContext ctx)
  • Return ValidationResult.Success if validation passes
  • Return a new ValidationResult object if validation fails
using System.ComponentModel.DataAnnotations;

    public static class PersonServerValidation
    {
        public static ValidationResult PostCodeExists(int postCode, ValidationContext validationContext)
        {
            // Here we call a Manager class that will return our boolean value
            // Any additional calls to class methods, or other services can be done here.

            AddressManager mgr = new AddressManager();
            bool exists = mgr.DoesPostCodeExist(postCode);

            if (!exists)
            {
                return new ValidationResult("The postcode entered is invalid.
                                            , new[] { validationContext.MemberName });
            }

            return ValidationResult.Success;
        }
    }

Finally, we can now update our PostCode property with the CustomValidation Attrubute. When RIA Services determine that validation of this property is needed, it will execute the Validation Method we declared above.

using System.ComponentModel.DataAnnotations;

    public class Person
    {
        //... other properties hidden ... //

        [CustomValidation(typeof(PersonServerValidation), "PostCodeExists")]
        public int PostCode { get; set; }
    }

So far we have been dealing with individual Entity Properties and its underlying validation processes. Alot of the times Property validation may be dependant on other Properties. For example, say that you wanted to validate the StreetName is a valid street in the Postcode specified; and that the street number is within the number of houses on that street. This is where we go one step beyond Property Validation to utilising Entity Validation.

Entity Validation

Entity Validation is pretty straight forward. It simply refers to the validation that takes place on an Entity Object as a whole, as opposed to validating individual Properties of that object. Entity Validation works in conjunction with Property Validation. Meaning that the Property Validations that you have defined in your class is still true and valid, and will automatically validate when required. Once all Property validation passes, the framework will then perform Entity Validation if one or more exist.

The process of defining a Validation Method for use with Entity Validation is similar to that described earlier. The only difference is that rather than having a parameter with the same type as the Property itself, we require a parameter of the Entity object instead. A sample Entity level Validation method is provided below:

using System.ComponentModel.DataAnnotations;

    public static class PersonServerValidation
    {
        public static ValidationResult StreetNameValid(Person person, ValidationContext validationContext)
        {
            AddressManager mgr = new AddressManager();
            bool validStreet = mgr.IsStreetValid(person.StreetName, person.PostCode);

            if (!validStreet)
            {
                return new ValidationResult("The street entered is not valid for with that postcode."
                                            , new[] { validationContext.MemberName });
            }

            return ValidationResult.Success;
        }

        public static ValidationResult StreetNumberValid(Person person, ValidationContext validationContext)
        {
            AddressManager mgr = new AddressManager();
            bool validStreetnumber = mgr.IsStreetNumberValid(person.StreetNumber
                                                            , person.StreetName
                                                            , person.PostCode);
            if (!validStreetnumber )
            {
                return new ValidationResult("The street number entered is not valid for that street
                                            , new[] { validationContext.MemberName });
            }

            return ValidationResult.Success;
        }
    }

The final step is to declare the Entity Validation for the Person class and link it to the corresponding Validation methods above:

using System.ComponentModel.DataAnnotations;

    [CustomValidation(typeof(PersonServerValidation), "StreetNameValid")]
    [CustomValidation(typeof(PersonServerValidation), "StreetNumberValid")]
    public class Person
    {
        //... other properties hidden ... //
    }

Validation via Invoke Methods

As briefly mentioned previously in this article, you can as a last resort create an Invoke method that will contain the logic you require for your validation. Using invoke methods for validation is often useful when you need to validate across entities, or if your design calls for out-of-the-ordinary situations that don’t tie into the scenarios listed above.

Conclusion

Well there you have it – a explanation of the validation framework available for you to use with the WCF RIA Services framework. As you can see, this validation framework works very well if you want to declare and keep all your validation logic within the mid-tier code that has been developed by your mid-tier developers. This removes the need for your UI developers to concern themselves with any of the business rules and validation logic that comes with it.

Traditional ASP.Net would have seen the duplication of your validation logic to the UI-tier making code maintenance extremely troublesome.

I hope this article has given you enough information to implement your own validation logic moving forward! :-)