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!
11/20/2010 3:51:44 AM #
Hello People! Your blog is awesome! I would like to visit it everyday. It's very informative and amazing
11/25/2010 11:02:06 AM #
thats good article!!
12/8/2010 2:59:52 PM #
kind of interesting and informative post thanks a lot for sharing it...
12/18/2010 7:44:14 AM #
J'aime vraiment ce type de n sujets ont un grand intérêt dans ce .... merci pour le partage ....
12/22/2010 11:58:50 AM #
This tutorial was really great and easily understandable for me.
12/24/2010 11:10:11 AM #
Good work done by the admin thanks for sharing the effort.
12/27/2010 2:15:29 PM #
It is because of helpful individuals like you that we are able to get the job done effortlessly. Thanks a lot mate.
12/30/2010 10:15:29 AM #
Congrats for advertisement such a advantageous blog. Your blog isn't abandoned advising but aswell acutely artful too. There usually are acutely brace of individuals who can abode not so simple online autograph that creatively. Keep up the adequate autograph !!
1/3/2011 9:10:47 AM #
Interesting articles are published here. By reading it I acquired great deal of knowledge on various subject.
1/6/2011 6:37:14 AM #
Cool dude, you have posted some interesting post.
1/7/2011 2:32:51 PM #

I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts
1/10/2011 3:52:41 AM #
Fluent Validation!! just what I was looking for. Thanks!
1/10/2011 11:03:43 AM #
Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your post.
1/11/2011 8:46:13 AM #
I always like your blog post because you always come with different ideas and information. I always shared your site post with my friends. Keep posting and i will follow you..
3/19/2011 10:25:34 PM #
Thanks for your strategies. One thing I've got noticed is that often banks and financial institutions know the spending routines of consumers and as well understand that a lot of people max out there their credit cards around the vacations. They smartly take advantage of that fact and commence flooding the inbox and also snail-mail box by using hundreds of no interest APR credit card offers just after the holiday season closes. Knowing that in case you are like 98% of all American general public, you'll jump at the chance to consolidate personal credit card debt and switch balances for 0 APR credit cards.
3/21/2011 10:51:27 PM #
I see there is some very good information in this article. Please continue with the work that you are doing
3/21/2011 10:59:14 PM #
I like your theme. Will be checking it out to see if I can use the same for my site. Very interesting site as well you have here.
3/21/2011 11:36:23 PM #
What can I say.  This article is pretty good compared to all the junk out there that I have seen.  
3/22/2011 6:39:03 PM #
French is a descendant of the Latin language of the Roman Empire, as are national languages such as Italian, Portuguese, Spanish, Romanian and Catalan, and minority languages ranging from Occitan to Neapolitan and many more. Its closest relatives however are the other langues d'oïl and French-based creole languages. Its development was also influenced by the native Celtic languages of Roman Gaul and by the (Germanic) Frankish language of the post-Roman Frankish invaders.
3/22/2011 8:33:28 PM #
I personally like the particular information and facts this excellent online site continuously supplies. Top-notch!
3/22/2011 11:10:25 PM #
I was recommended this website by my cousin. I am not sure whether this post is written by him as no one else know such detailed about my problem. You're amazing! Thanks!
3/23/2011 12:05:54 AM #
It is actually funny that you should write about this since I was basically just wondering about it the other day. You have portrayed my opinions exactly. Nicely.
3/23/2011 2:53:31 AM #
I loved as much as you'll receive carried out right here. The sketch is attractive, your authored subject matter stylish. nonetheless, you command get got an edginess over that you wish be delivering the following. unwell unquestionably come further formerly again as exactly the same nearly a lot often inside case you shield this increase.
3/23/2011 4:40:55 AM #
I think this is among the most significant info for me. And i'm glad reading your article. But wanna remark on some general things, The website style is ideal, the articles is really excellent : D. Good job, cheers
3/23/2011 5:19:43 AM #
Wonderful beat ! I would like to apprentice while you amend your website, how can i subscribe for a blog website? The account helped me a acceptable deal. I had been tiny bit acquainted of this your broadcast offered bright clear concept
3/23/2011 6:40:53 AM #
come to my site tattoo
8/5/2013 6:10:58 PM #
Pingback from hirendhara.biz

How do I get rid of the dot in the PropertyName of a fluent ValidationResult | Q Sites
Comments are closed