views:

1333

answers:

2

Hello

I'm using dataannotations to check data thats being entered, but I'm stuck when it comes to more custom way to validate data.

I need to run queries against database to see if stuff exists there or not, and then report back to user if a "custom db-check error" appears, such as "The Companyname already exists"

How can I implement such a thing together with dataannotations?

I have all the queries done etc using linq and entity framework that comes with 3.5sp1

/M

+6  A: 

Custom attributes that extend data annotations

You will have to write your own attributes that will do the validation of your object instance against data store.

Make sure your classes inherit System.ComponentModel.DataAnnotations.ValidationAttribute class:

public class MustNotExist: ValidationAttribute
{
    ...
}

Caution

I've run into a similar situation when I needed to validate that the object is unique within data store. But this kind of validation wasn't possible on the entity class itself, since it should only work for those entities that are being created but not when you return your entity from the data store already.

My solution was to have a separate interface, class and attribute.

public interface IExternalValidator ...

class DBUniqueValidator: IExternalValidator ...

class ValidateExternallyAttribute: FilterAttribute, IActionFilter
{
    ...
    public ValidateExternallyAttribute(Type validatorType, Type entityType) ...
    ...
}

I was able to place my attribute on controller actions that get entity parameters. Filter action attribute then checks controller action parameters (it can easily access their types and values) and runs external validator against correct parameters (provided types in attribute definition) and populates ModelState errors when validation fails.

[ValidateExternally(typeof(DBUniqueValidator), typeof(User))]
public ActionResult RegisterUser(User newUser)
{
    if (!this.ModelState.IsValid)
    {
        // act accordingly - probably return some error depending on model state errors
    }
    // register new user in data store
}

This way I was able to run external validation only on those actions that actually needed it, and this technique also helped my controller actions code to stay clean and short. All I had to do is to check if there are any model state errors.

Robert Koritnik
Great answer. I was aware of the Custom Validation Attributes but the external validator is a great solution. I had a custom validation attribute to check if an email already exists in the system. This works great when a user want to join/subscribe to your site as you don't want to register an preexisting account but what happens when the same user just wants to sign-in? Of course the email already exists then. Perfect solution for that issue, thanks!
Dave Jellison
Very interesting, would be helpful to see a more complete example. I get the idea but don't understand it completely. (the second solution)
Aros
@Aros: I've explained the solution a bit more and added usage example on some controller action. I hope that helps clearing up things a bit more.
Robert Koritnik
A: 

Hi,

@Robert Koritnik, can you please put a full example of the code you used within the interface, class and attribute for this example please-please!

Cheers

shahid81
@shashid81: Unfortunately I'm not on that project any more so I can't provide any real-life code. But I was thinking of this right now and interface could be generic.
Robert Koritnik