Home >

Fluent Validation With ASP.NET MVC and Db4o

10. February 2009

UPDATE 3: Exception throwing for business rules is not a good practice, making this post almost useless.
UPDATE 2: Did you notice the duplication in event handling?
UPDATE 1: Jeremy Skinner was kind enough to respond to my feature request, please look at the first block. Thanks Jeremy!

I have been trying to implement validation for BlogSharp. There are several validation frameworks including Castle Validator but it didn’t feel good to put attributes on the entity itself. I wondered if there is a 3.5 style of doing it and thankfully Jeremy Skinner provided a good framework that uses Lambda Expressions which is called Fluent Validation. Its syntax is very similar to the that of Fluent NHibernate.

public class PostCommentValidator : ValidatorBase<PostComment>
{
    public PostCommentValidator()
    {
        RuleFor(x => x.Comment).NotEmpty();

        RuleFor(x => x.Email).NotEmpty();
        RuleFor(x => x.Email).EmailAddress();        RuleFor(x => x.Email).NotEmpty().And().EmailAddress();
        RuleFor(x => x.Web).Url().When(x=>!string.IsNullOrEmpty(x.Web));
    }
}


It is also easy to extend its validation capacities. All you need to do is to implement IPropertyValidator<T>. For my case, I needed to have Url validation and it was enough to inherit from RegularExpressionValidator.

public class UrlValidationRule<T>:RegularExpressionValidator<T>
{
    public UrlValidationRule():base(@"URLRegularExpressionHere")
    {
        
    }
}


You may also want to create an extension method in order to have a uniform syntax.

public static class UrlValidationExtension
{
    public static IRuleBuilderOptions<T, string> Url<T>(this IRuleBuilder<T, string> ruleBuilder)
    {
        return ruleBuilder.SetValidator(new UrlValidationRule<T>());
    }
}


There are some additions that i made in ValidatorBase<T>. Currently it returns ValidationResult, which has all the information about the validation process. I made it throw Exception in order not to deal with layering.

Nothing very special up to this point.

What I wanted to tell in detail today is how to implement validation using Db4o, Castle and Fluent Validation stack. Even though I was to do the validation at Service level, I decided that it may be better to have it at persistence level.

Db4o has events (did I mention that I like events?) that take place after and before various operations including Activate, Create, Update, Delete, Commit. The best place to implement this validation is to use the events Creating and Updating which are raised_before_ the updated/added object is stored back in Db4o. I needed a way to integrate them with my home made Db4o Facility that was inspired by Castle NHibernate Integration. I created an interface like the one below

public interface IDb4oInitializationHandler
{
    void HandleObjectContainerCreated(IExtObjectContainer extObjectContainer);
}


Implementors will be called just after the IObjectContainer so that we will have the opportunity to wire up our events. Currently you can’t specify a specific InitializationHandler for a specific container, but I plan to implement it soon.

public void HandleObjectContainerCreated(IExtObjectContainer extObjectContainer)
{
    var factory = EventRegistryFactory.ForObjectContainer(extObjectContainer);
    factory.Creating += ValidationHandler;
    factory.Updating += ValidationHandler;
}protected void ValidationHandler(object sender, CancellableObjectEventArgs args)
{
    try
    {
        ValidateObject(args.Object);
    }
    catch(ValidationException ex)
    {
        args.Cancel();
        throw ex;
    }
}


and in the handlers of the events, I check if the stored object has validator associated with it and then validate.

protected virtual void ValidateObject<T>(T obj)
{
    var type = obj.GetType();
    var validatorType=typeof (IValidatorBase<>).MakeGenericType(type);
    if(container.HasComponent(validatorType))
    {
        var validator = container.Resolve(validatorType) as IValidatorBase;
        validator.ValidateAndThrowException(obj);                
    }
}


The exception is caught at the Controller, then is passed to the ModelState.

try
{
    postService.AddComment(comment);
}
catch(ValidationException vex)
{
    this.ModelState.AddValidationExceptionToModel("comment",vex);
}
            


AddValidationExceptionToModel is an extension method

public static void AddValidationExceptionToModel(this ModelStateDictionary model, string prefix,ValidationException exception)
{
    var errors=exception.Errors;
    foreach (var error in errors)
    {
        model.AddModelError(string.Format("{0}.{1}",prefix,error.PropertyName), error.Message);
    }
}

 

The result is the following:


It is as easy as this, thanks to the extensibility of Db4o and Fluent Validation frameworks.

If you like it, don't forget to kick and/or shout it

kick it on DotNetKicks.com Shout it

, ,

Comments

2/10/2009 3:42:59 AM #
Trackback from DotNetKicks.com

Fluent Validation With ASP.NET MVC and Db4o
2/10/2009 7:39:47 AM #
Trackback from DotNetShoutout

Fluent Validation With ASP.NET MVC and Db4o
2/10/2009 5:20:56 PM #
Hi Tuna,
Great alternative method to using Castle Validator, however - I think it should feel good to put validation attributes on the entity classes themselves as this is describing your data model. You also describe your model with the properties that should be included and their associated data types.  If you are defining the data's type, should you not also define it's rules and regulations at the same point? This will be your single point of reference you will always refer to.   For instance, if your data model objects reflect database columns and you have a varchar(100) field, you will and could not ever accept varchar(200) or potentially never want nulls, therefore if we realise we basically want to reflect these rules in .NET, the closer area in which we can do that is in the DAL.  Then when called upon, the model would be delivered with all rules in place.

Kind regards,
Graham O'Neale
2/10/2009 7:59:16 PM #
Hi Graham,
Yes, you are absolutely right, this is one of the things that made me think a lot before i put rules in another class. Steve Sanderson made me believe that this is right, and I still think that this is right. However, I don't want to put attributes on my entities even though I don't have any reason not to. I am doing the validation in DAL (well not really in dal, but just before the object is stored, the good thing is they are _automatically_ validated).

Thanks, and Regards!
2/10/2009 10:19:16 PM #
And more importantly, It allows me to do this kind of stuff

RuleFor(x => x.Web).Url().When(x=>!string.IsNullOrEmpty(x.Web));

which may be harder to implement using attributes(you need to specify another attribute etc)
2/11/2009 3:53:29 AM #
If you want to build the validation rules into your entity then there's nothing to stop you from doing so:

public class Customer {
...private static AbstractValidator<Customer> validator = new InlineValidator<Customer>();
  
...static Customer() {
......validator.RuleFor(x => x.Name).NotNull();
...}

...public ValidationResult Validate() {
......return validator.Validate(this);
...}

...public string Name { get; set; }
  
}

(InlineValidator just inherits from AbstractValidator). You could also expose the Validate() method on your entity in an interface (eg IValidatable) that can be called from your repository's save method.

I think attributes are fine for simple validation rules, but as soon as you get into more complex scenarios then you lose type safety. For example, take a look at Castle's NotSameAsValidator. If you want to compare one property to another, you have to specify the property name as a string. The idea behind FluentValidation is that it allows you to define more complex rules in an expressive, type-safe manner.

Jeremy
2/11/2009 3:58:23 AM #
Cool post and very relevant for me at this point in time as i'm working on a tagging interface built in MVC.

I love this extensibility and the cleanness of the solution. At this moment i use LLBLGen Pro as OR/M and implemented my own validation conform their ValidationBase. I'll reconsider that approach, even-though MVS now also support the IDataError (or something like that) implementation, which makes using the llbl entity validation even more seamless. The AddValidationExtensionExceptionToModel is something i haven't implemented yet, but sure as hell will!

Personally i also like to have my validation rules in a separate class and not directly within the entity. I think that both classes exist for different reasons and thus should not be one and the same.
2/12/2009 1:31:36 AM #
Hi Tuna,

In my opinion, exception handling should be used for dealing with exceptional cases not for driving the normal flow of your application, like you are doing here for implementing your entities validation.
Failure to connect to the underlying repository, configuration error, etc... those are exceptional cases; Rules execution is not exceptional at all, it's just another piece of your domain model.

Anyway, I've been following your blog lately and I think that you are doing a good job, keep it up!

Javi
2/12/2009 3:46:04 AM #
Trackback from Community News

Fluent Validation With ASP.NET MVC and db4o
2/12/2009 6:59:15 AM #
Hi Javier,
You're damn right, I will need to change this approach soon, but not sure how soon Smile. You're right that exceptions should be used for real exceptions, and a validation is not an exceptional case. Do you think that I should go with the approach that uses the return value of Validate? Do you think that I should use it at Service level?

Thanks for your input, and following me!
2/12/2009 8:06:39 AM #
Hi Tuna,

I'd put validation in your service layer, as now you're coupling the entity validation with your underlying repository implementation details (Db4o events)

In my opinion the return value is just alright, then in order to bubble up the validation results from your service layer to UI layer you can define and use an operation result class where you can include the overall result (succeeded, failed - an enumeration maybe) and the validation messages...
If on top of that you want to return an object from your service method you can create a "generic operation result" class which extends the former with a generic property.

Just brainstorming!


2/12/2009 8:11:17 AM #
Hi Javier,

Db4o events are cool and all i need to do is that imeplement that event wiring stuff for a specific provider. I can do the same thing with NH, or probably with home made stuff, but this would mean that i need to duplicate the things.

I need to have some time to try out the ideas!
2/15/2009 6:54:23 PM #
Hi Tuna,

That's a nice article you have!

Yet, it is better to get rid of the Exceptions (unless rules are used to validate method arguments) and provide stronger linking to the UI. That helps in complex production scenarios.

Here are bits from my validation framework that might give you some ideas:
abdullin.com/.../...dation-and-business-rules.html

And the binding to UI with it (MVC manner):
abdullin.com/.../...iven-ui-validation-in-net.html


What do you think?

Best regards
2/17/2009 5:47:39 PM #
I'll check it out soon.
Thanks!

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading