LA.NET [EN]

Apr 26

One of the nice things you can do to improve the code we’ve seen in the previous post is define the validation rules in an external assembly. By doing this, you can change your rules without having to recompile the assembly that contains the domain objects. To illustrate this, we’ll change the example presented in the last post.

The first thing we’ll do is create a new class library assembly to host our Student class. I’m calling it OO and changing the default namespace of the Student class:

namespace OO {
    public class Student     {
        public Student(Int32 studentId) {
            StudentId = studentId;
        } 
        public Int32 StudentId { get; private set; }
        public String Name { get; set; }
        public String Email { get; set; }
    }
}

Then, we need another (class library) assembly which references NHibernate.Validator and our OO assemblies. This is where we’ll put our validation rules. In this case, I’ve called the assembly OO.Rules and I’ve decided to go with the fluent interface approach. Here is the code of the StudentRules class (which has all the validation rules for the Student class):

namespace OO.Rules {
    public class StudentRules: ValidationDef<Student>    {
        public StudentRules()        {
            Define(st => st.StudentId).GreaterThanOrEqualTo(1)
                                                     .WithMessage("StudenId must be positive");
            Define(st => st.Name).NotEmpty()
                                              .WithMessage("Name cannot be empty")
                                              .And.NotNullable()
                                              .WithMessage("Name cannot be null");
            Define(st => st.Email).IsEmail().WithMessage("Email is not correct");

        }
    }
}

Finally, I’m building a console app for testing the code. After adding all the necessary references (don’t forget to reference our 2 custom assemblies and the NH validator assembly), you’ll only need this code for getting the same results we had with the previous posts:

var fluentConfig = new FluentConfiguration();
((IMappingLoader)fluentConfig).AddAssembly("OO.Rules");
fluentConfig.SetDefaultValidatorMode(ValidatorMode.UseExternal);
var validator = new ValidatorEngine();
validator.Configure(fluentConfig);

var student = new Student(-1) {
                Name = "Luis",
                Email = "labreu"
};

var invalidValues = validator.Validate(student);
//same code as before

As you can see, the main difference (when compared with the previous example) happens in the setup of the FluentConfiguration instance. Instead of registering each validated type, we’re simply passing the name of the assembly and letting the framework pick all the types and their validation rules.

In my opinion, this approach (of separating rules from validated objects) has two advantages:

  • you can easily change the rules without needing to recompile the assembly that contains your objects;
  • the OO assembly no longer needs to reference the NH validator assembly.

And that’s it for today.

1 comment so far

  1. Fabio Maulo
    6:18 am - 6-7-2009

    Only to say that the correct way to register all definition in an assembly via “Loquacious” is:
    var configure = new FluentConfiguration();
    configure.Register(Assembly.GetExecutingAssembly()
    .ValidationDefinitions())
    .SetDefaultValidatorMode(ValidatorMode.UseExternal);

    ValidationDefinitions is an extension method for Assembly.

    If you want Register from a specific assembly
    configure.Register(Assembly.Load(“NHibernate.Validator.Tests”)
    .ValidationDefinitions())
    .SetDefaultValidatorMode(ValidatorMode.UseExternal);

    You have even ValidationDefinitions as extension of IEnumerable
    so you can do something like this
    configure.Register(
    Assembly.GetExecutingAssembly().GetTypes()
    .Where(t => t.Namespace.Equals(“Company.Product.YourNamespace”))
    .ValidationDefinitions())
    .SetDefaultValidatorMode(ValidatorMode.UseExternal);

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>