Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Introducing a validation library

5.00/5 (3 votes)
28 Oct 2010LGPL32 min read 12.4K  
Introducing a validation library

I've made a validation library which is focusing on model validation. Why another one when there are a few good ones like EntLib Validation ApplicationBlock and Data Annotations?

There are three reasons...

1. It's Extendable

You can easily extend the library in different ways.

Own Validation Rules

You can create your own rules in the following way:

C#
public class CoolnessRule : IRule
{
    public string Format(string fieldName, IModelLanguage rulesLanguage)
    {
        return string.Format(rulesLanguage["Coolness"], fieldName);
    }

    public bool SupportsType(Type type)
    {
        return type == typeof (string);
    }

    public bool Validate(object value)
    {
        return value.ToString() == "Jonas";
    }
}

The Format method is used when formatting and localizing error messages. Each rule can be more or less complex and might add range restrictions, etc. Therefore, it’s up to the rule to pull the language prompt (in this case “‘{0}’ must be called ‘Jonas’ to be cool“) and add the correct number for parameters.

The SupportsType method is used to determine if the specified type can be validated by the rule. For instance, the Max rule can validate all primitive types and strings (string length).

Validate method does the actual validation.

Validate in Different Ways

The actual validation can be done in different ways. Fluent and attribute validations are built in, more about them later. To add your own validation provider, do something like this:

C#
class MyRuleProvider : IRulesProvider
{
    public bool Contains(Type type)
    {
        return type == typeof (Model2);
    }

    public ModelValidator Create(Type type)
    {
        ModelValidator validator = new ModelValidator();
        validator.Add("FirstName", new RequiredRule()); // first name is required
        validator.Add("Department", new BetweenRule(5, 20)); // department must be 
						// between 5 and 20 letters.
        validator.Add("Age", new BetweenRule(18, 65)); // age must be between 
						// 18 and 65 years.
        return validator;
    }
}

The Contains method determines if this provider has support for the specified type. And the Create method is used to create the ModelValidator class containing all the rules.

Then, you just need to add your provider to the library:

C#
Validator.Add(new MyRuleProvider());

2. It’s Multilingual

The multilingual support is quite flexible too. You can easily load language from any source you want. I myself am using text files to be able to categorize entries and use one file per model (I use the translation files for other stuff too, for instance localized error messages).

To load strings from a StringTable, you can do something like this:

C#
public class LanguageProvider : ILanguagePrompts
{
    public string this[string modelName, string promptName]
    {
        get { return Get(modelName, promptName) ?? "[" + promptName + "]"; }
    }

    public string Get(string modelName, string promptName)
    {
        return Resource1.ResourceManager.GetString(modelName + "_" + promptName);
    }
}

And to use your provider:

C#
Validator.LanguageHandler = new LanguageProvider();

In your string table, you create entries like the following ones:

User_FirstName             FirstName
User_LastName             LastName

i.e. ModelName underscore PropertyName.

3. It’s Flexible

The library doesn’t force you to use validations in a certain way. You can use your own favorite way of creating validations.
The two built in providers use either code or attributes to provide validations.

Attribute Validation

C#
public class MyModel
{
  [Required]
  public string FirstName {get;set;}

  [Required, Min(15)]
  public string LastName {get;set;}
}

FirstName is required and LastName is required and must be maximum 15 characters long.

Your own validation rules will automatically be added to the validator when using attribute validation.

Fluent Validation

Fluent validation means that you create a class which is used to validate models. The class is automatically loaded and instantiated by the library, all you need to do is to create it and place it in the same namespace as the model. It should be named [YourModelName]Validator, i.e. UserValidator.

C#
public class MyModelValidator : FluentValidator<MyModel>
{
  public MyModelValidator()
  {
    Property("FirstName").Required();
    Property("LastName").Required().Min(15);
  }
}

To add support for your own validation rules, simply create extension methods for the Property class:

C#
public static Property Tired(this Property instance)
{
  instance.Add(new TiredRule());
  return instance;
}

Usage

The most important part is how the library is used, right?

C#
User user = new User();
user.FirstName = "Jonas";

var errors = Validator.Validate(user);
if (errors.Count > 0)
{
    // Handle the errors in any way you like.
    // both property names (localized and actual property name) 
    // and localized error message is accessible.
}

Source Code

The source code can be found at CodePlex.

Share and Enjoy:PrintDiggStumbleUpondel.icio.usFacebookYahoo! BuzzTwitterGoogle BookmarksDZoneLinkedInSlashdotTechnorati

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)