Contacting database from within data validation attribute

1k views Asked by At

I have a clientside typeahead that pulls back a json list and presents options to the user for a specific list of places that they can enter for an input field.

On the server I want to make sure that the submitted form data matches one of these places. Realistically it should unless someone was being malicious and posting data from fiddler or something like that.

I supply the data to the typeahead from a list stored in Redis. I've read that it's bad practice to contact a database from within an attribute but I would like to check for the existence of the place in the redis list before allowing the logic flow to continue.

I could cache the list statically on startup in each webserver instance however this now means that if the list changes at all then all the servers would have to be restarted to get the changes.

Perhaps instead of using Validation Attributes I should be using a fluent validator?

http://fluentvalidation.codeplex.com/wikipage?title=ValidatorFactory&referringTitle=Documentation

1

There are 1 answers

1
kaptan On

I've read that it's bad practice to contact a database from within an attribute [...]

Your attribute does not need to know about any database or anything of that matter. What your attribute needs to do is to call a Service to do the job. The implementation of the Service will be hidden from your Attribute's point of view.

interface IValidationService
{
    bool DoesPlaceExist(Place place);
}

class RedisValidationService : IValidationService
{
    bool DoesPlaceExist(Place place)
    {
       // crazy redis magic ...
    }
}


class PlaceValidationAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {    
       var validationService = new RedisValidationService();  // ideally use IoC
       var isValid = validationService.DoesPlaceExists(new Place(value)); 
       // ... this is over simplified to just show the idea
       // return blah blah 
    }