Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom validation with Data annotations

I'm using data annotations to check data that's 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

like image 475
Lasse Edsvik Avatar asked Dec 15 '09 07:12

Lasse Edsvik


People also ask

How do you validate data annotations?

DataAnnotations namespace includes the following validator attributes: Range – Enables you to validate whether the value of a property falls between a specified range of values. RegularExpression – Enables you to validate whether the value of a property matches a specified regular expression pattern.

Can we do validation in MVC using data annotations?

In Asp.net MVC, we can easily apply validation to web application by using Data Annotation attribute classes to model class. Data Annotation attribute classes are present in System.

Can we create custom data annotations?

The MVC framework has great extensibility features and because of this we can create our own customized data annotation attributes.


1 Answers

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.

like image 150
Robert Koritnik Avatar answered Nov 12 '22 23:11

Robert Koritnik