Geeks With Blogs
// ThomasWeller C#/.NET software development, software integrity, life as a freelancer, and all the rest

Validation is one of the most important objectives when crafting a domain. You have to shelter your domain objects from undesirable property and method argument values as well as being able to explicitly validate an object's state in certain situations, for example to enforce business rules. My preferred way to do this is with the ValidationAspects aspect library, that sits on top of the PostSharp aspect weaver and allows for placing Design by Contract - style attributes on properties and method arguments, thus getting rid of most of the usual 'error checking/exception throwing' code and greatly improving the readability of your code; you may even write your own custom validation aspects, if required. I already showed a very simple and short example in a previous post.

(There are a couple of other solutions available for validation, like e.g. NHibernate.Validator, the Validator Toolkit for ASP.NET MVC, or Spring.Aop, to name just a few. The main reason for me to use PostSharp + ValidationAspects is that it is not restricted to a specific technology or layer (and thus naturally fits into the Domain Driven Design methodology) , and that it doesn't rely on some sort of runtime proxies, but generates native IL code...) 

This is the first post of a three-part series that discusses the use of these validation aspects throughout the different layers of an application. Each part will cover a separate layer as follows:

  • The first part (this one) will show in some detail how validation aspects can be applied to the domain layer's business objects both for property value/argument interception and object state validation.
  • The second part then will look at how these validations can be integrated with a persistence layer that's using NHibernate.
  • The third part finally will use the validation aspects to perform client-side validation in an ASP.NET MVC GUI. The xVal framework is used to bring the server-side validations to the web pages.

The "business class"

Throughout these posts, I will use the here shown Person class as my "domain". It may be a bit silly at some points, but generally it serves our demonstration purposes well, I think. Here it is, along with some requirement definitions:

PersonClass

  • A person's Age must be between 18 and 65 years.
  • Both FirstName and LastName must have a value and must not exceed 50 characters in length.
  • The Company value must not be longer than 128 characters, if set.
  • The person's Email address must not be longer than 50 characters and must conform to the general scheme x@y.z, if set.
  • A person's parents (Father+Mother) can only be set together (i.e. there can be no Father without Mother or vice versa).
  • A person is said to be 'valid' if:
    • The Email is either empty or it has the form firstname.lastname@company.com.
    • Its parents are either not set or they are also valid according to the above definition.

The Person class provides a way to explicitly check its validity according to the above definitions.

 

Validating properties

Ok now, let's begin to implement this, using Gallio/MbUnit to test-drive the above features. The "test" for the Age property will look like this:

[VerifyContract]

public readonly IContract VerifyAge = new AccessorContract<Person, int>

{

    PropertyName = "Age",

    ValidValues = { 18, 65 },

    InvalidValues =

    {

        { typeof(ValidationException), 17, 66 }

    }

};

As you can see, putting a property under test has become quite simple with the latest version (3.1): You don't have to define a test method anymore, instead you only declare an AccessorContract verifier of the required type and name, together with the values that you want to be tested against the property setter and the exception type that you expect to be thrown for a certain invalid value.

To make the above test pass, we only have to decorate the Person's Age property with the InRange validation attribute:

[InRange(18, 65)]

public int Age

{

    get { return this.age; }

    set { this.age = value; }

}

This is the most basic (and probably most common) usage scenario for the attributes of the ValidationAspects library: You just declare what you (don't) want, and that's it. Simple, expressive and clean...

(You may notice from the above snippet that I'm using properties with backing fields instead of the much shorter auto-properties. This is intentional, because I'm planning to use NHibernate for persistence later on, where this will become beneficial. More on that in the next post...)

Ok now, let's move on. One restriction, that MbUnit's AccessorContract verifier has in its current version, is that it only accepts an ArgumentNullException when testing a null value against the respective property. Because my code will always throw a subclass of ValidationException, I'm forced to use 'traditional' test methods for all properties that don't accept a null value. These are, for example, the tests for the FirstName property:

[Test]

[Row(null), Row("")]

[Row("123456789012345678901234567890123456789012345678901")]

public void VerifyFirstName_InvalidValues(string name)

{

    Person person = new Person();

    Assert.Throws<ValidationException>(() => person.FirstName = name);

}

 

[Test]

[Row("Hans-Jürgen")]

[Row("12345678901234567890123456789012345678901234567890")]

public void VerifyFirstName_ValidValues(string name)

{

    Person person = new Person();

    person.FirstName = name;

    Assert.AreEqual(name, person.FirstName);

}

And this is the code that will satisfy these tests:

[MaximumLength(50), NotNullOrEmpty]

public string FirstName

{

    get { return this.firstName; }

    set { this.firstName = value; }

}

The last thing, that may be interesting here, is that there is (among many others) also a validation aspect available that allows you to define a custom regular expression. I used it to enforce the proper format for the Email property:

[MaximumLength(50)]

[MatchesRegex(@"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z0-9]{2,5}$")]

public string Email

{

    get { return this.email; }

    set { this.email = value; }

}

So far, so good - you get the picture.  The rest of the property validations can be seen in the sample solution, which is available here...

Validating method arguments

One of the above stated requirements was: "A person's parents (Father+Mother) can only be set together". We implement this by having only getters on the Father/Mother properties and defining a SetParents() method, that does not accept null values:

public Person Mother { get { return this.mother; } }

public Person Father { get { return this.father; } }

 

public void SetParents([NotNull]Person mother, [NotNull]Person father)

{

    this.mother = mother;

    this.father = father;

}

As you can see, method parameter validation works exactly like property validation: You just have to apply the validation attribute(s) to the argument declarations, and you're done. So there's not much to say here...

Validating an object's state

Apart from intercepting values, it is sometimes necessary to explicitly verify an object's state. With the ValidationAspects library, this becomes as simple as this:

[Test]

public void PersonDoesNotValidate()

{

    var person = CreateInvalidPerson();

 

    ValidationResult result = person.Validate();

 

    Assert.IsFalse(result.IsValid,

                   "Object validation succeeded, but was expected to fail.");

}

Validate() is an extension method on the object type. Its invocation results in custom validation methods being called, which are methods decorated with the ValidationMethod attribute. They should be static, have the void return type, have one parameter of the type of the validation target, and should throw a ValidationException derived exception for a failed validation. (By default,  Validate() will also invoke the object's property validators.) Here's an example that implements the requirement "The Email is either empty or it has the form firstname.lastname@company.com":

[ValidationMethod]

public static void ValidateEmail(Person person)

{

    if (!string.IsNullOrEmpty(person.Email))

    {

        string firstName = NormalizeString(person.FirstName);

        string lastName = NormalizeString(person.LastName);

        string company = NormalizeString(person.Company);

        string expectedEmail = firstName + '.' + lastName + '@' + company + ".com";

 

        if (!person.Email.Equals(expectedEmail, StringComparison.InvariantCultureIgnoreCase))

        {

            throw new ValidationException("Email address should be '" + expectedEmail + "'.");

        }

    }

}

To satisfy the "Its parents are either not set or they are also valid according to the above definition" requirement, we simply define a second validation method, that "cascades" the validation to the parents (you can have as much validation methods as required), should they be set:

[ValidationMethod]

public static void ValidateParents(Person person)

{

    if (person.Father != null)

    {

        ValidationResult result = person.Father.Validate();

        if (!result.IsValid)

        {

            throw new ValidationException("'Father' did not validate.", result.ValidationException);

        }

    }

    if (person.Mother != null)

    {

        ValidationResult result = person.Mother.Validate();

        if (!result.IsValid)

        {

            throw new ValidationException("'Mother' did not validate.", result.ValidationException);

        }

    }

}

Finally, we modify our SetParents() method such that it accepts only valid Person instances. Here's the final version:

public void SetParents([NotNull]Person mother, [NotNull]Person father)

{

    ValidationResult result = mother.Validate();

    if (!result.IsValid)

    {

        throw new ValidationException("Argument 'mother' did not validate.", result.ValidationException);

    }

 

    result = father.Validate();

    if (!result.IsValid)

    {

        throw new ValidationException("Argument 'father' did not validate.", result.ValidationException);

    }

 

    this.mother = mother;

    this.father = father;

}

Writing your own custom validators

The ValidationAspects library comes with a lot of predefined validators, but occasionally you might not find what's required for a certain scenario. In this case, it's quite easy to write a custom validation aspect (a more detailed HowTo can be found here.)

To demonstrate this, I added a Gender (Male|Female) enum to my "domain model" and a Gender property to the Person class. Here's the test for that property:

[VerifyContract]

public readonly IContract VerifyGender = new AccessorContract<Person, Gender>

{

    PropertyName = "Gender",

    ValidValues = { Gender.Female, Gender.Male },

    InvalidValues =

    {

        { typeof(ValidationException), (Gender)(-1) }

    }

};

As you probably know, the somewhat dangerous thing about using enums is that it's relatively easy to introduce false numerical values. So I thought it might be a good idea to have a validation attribute that checks if a property/argument really is an enumeration value of the desired type. The following shows the usage of the EnumValue attribute when applied to the Gender property:

[EnumValue(typeof(Gender))]

public Gender Gender

{

    get { return this.gender; }

    set { this.gender = value; }

}

Writing a new, custom validation attribute (in its most basic form) is relatively easy and straightforward. First you have to implement an IValidatorFactory derived type to provide your validation function, using lambda syntax:

public class EnumValue : IValidatorFactory

{

    public Type EnumType { get; set; }

 

    public IValidator<T> Create<T>()

    {

        return new Validator<T>((@value, @context) =>

        {

            if (!Enum.IsDefined(EnumType, @value))

            {

                throw new ValidationException(string.Format(

                    "'{0}' is not a valid value for enumerations of type '{1}'.",

                    @value,

                    EnumType.FullName));

            }

        });

    }

}

Then you define a ValidatorAttribute derived attribute that returns this factory:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]

public class EnumValueAttribute : ValidatorAttribute

{

    private readonly Type enumType;

 

    public EnumValueAttribute(Type enumType)

    {

        if (enumType == null)

        {

            throw new ArgumentNullException("enumType");

        }

        if (!enumType.IsEnum)

        {

            throw new ArgumentException(string.Format(

                     "'{0}' is not an enumeration type.", enumType.FullName));

        }

        this.enumType = enumType;

    }

 

     public override IValidatorFactory Factory

    {

        get { return new EnumValue {EnumType = this.enumType}; }

    }

}

That's all that is required to make the validation attribute work, although there can (and probably should) be done a little bit more, if you want to provide a more general solution (e.g. you should define a custom ValidationEcxeption type to allow for custom message formatting).

The sample solution

As usual, I provided a sample solution (VS 2008), which you can download from here. It contains the here shown Person/Gender "domain", the demonstrated EnumValue validator, and a test project with a complete set of relating unit tests.

 

kickit
shoutit
delicious facebook digg reddit linkedin stumbleupon technorati mrwong yahoo google-48x48 twitter email favorites
Posted on Sunday, November 15, 2009 1:57 PM Readability , Architecture and Design , Aspect-oriented programming | Back to top


Comments on this post: Validating business objects with AOP (1: the domain)

# re: Validating business objects with AOP (1: the domain)
Requesting Gravatar...
"The main reason for me to use PostSharp + validation aspects is that it is not restricted to a specific technology or layer"

I am sorry I didn't understand the above statement. Isn't using postsharp and validation aspects itself being restricted to a specific technology or layer?

What is the difference between using a castle library vs postsharp + validation aspects?
Left by Kiran on Nov 16, 2009 1:45 PM

# re: Validating business objects with AOP (1: the domain)
Requesting Gravatar...
Kiran,

of course VA/PostSharp is a technology itself.

What I meant is, that it doesn't restrict you to a certain GUI technology like ASP.NET MVC, WPF or WinForms; or to a certain ORM technology like NHibernate, Linq2Sql or whatever.

It's pure POCO-oriented programming that can be used with everything.
Left by Thomas Weller on Nov 16, 2009 1:55 PM

# re: Validating business objects with AOP (1: the domain)
Requesting Gravatar...
Thank you for this post. I had heard about PostSharp and this is one area where AOP might become useful.

How do you feel this approach compares to Microsoft approach to Design By Contract, that is MS Code Contracts? Have you tried that also?
Left by Stefano Ricciardi on Nov 18, 2009 2:04 PM

# re: Validating business objects with AOP (1: the domain)
Requesting Gravatar...
Stefano,

I didn't try MS Code Contracts yet. So there's not much that I can say about it except that it looks interesting. This post compares the two (earlier version): http://thetreeknowseverything.net/2009/01/25/state-vs-interception-validation-vs-code-contracts.

- Thomas
Left by Thomas Weller on Nov 18, 2009 4:19 PM

Your comment:
 (will show your gravatar)


Copyright © Thomas Weller | Powered by: GeeksWithBlogs.net | Join free