The Castle Validator component

February 4th, 2007

A few weeks ago I introduced a new project o Castle’s trunk: Castle.Components.Validator. This was supposed to go to the Castle.Core, but to prevent the third world war from starting on castle mailing list, I decided to go with a separated assembly. This project has no dependencies, and can be used on a variety of projects and environments. I’ll try to explain the basics here and see what happens.

What itchy it scratches

The project’s goal was to create a thin, lightweight and flexible validation framework. Validation rules are – conceptually – attached to Types. The standard way is to use attributes, but they are not obligatory.

How does it work

The main entity is the ValidatorRunner, and it requires an IValidatorRegistry instance. The registry keeps the set of validators associated with a type and its properties. Out of box there’s a CachedValidationRegistry implementation which uses reflection. If you’re a xml fanatic, you can create a IValidatorRegistry implementation that reads from a xml file.

For performance reasons you should only have a single IValidatorRegistry instance. The ValidatorRunner should be created per activity, as it is stateful.

Using it

To use the Validator you just need to instantiate the runner and use one of the IsValid overload:

ValidatorRunner runner = new ValidatorRunner(new CachedValidationRegistry());

if (runner.IsValid(customer))
{
	// do something with customer
}
else
{
	MessageBox.Show("Whoops!");
}

After invoking the IsValid you can use the GetErrorSummary(instance) to grab a detailed list of what went wrong.

The validators

A validator is just an ordinary class that implements the IValidator attribute. The important method is the IsValid. The code for NonEmptyValidator follows:

public class NonEmptyValidator : AbstractValidator
{
	public override bool IsValid(object instance, object fieldValue)
	{
		return fieldValue != null && fieldValue.ToString().Length != 0;
	}

	..
}

The attributes

If you create a new validator, you’d usually use an attribute to associate it with a property. The attribute is required to implement IValidatorBuilder. The implementation for ValidateNonEmptyAttribute follows:

public class ValidateNonEmptyAttribute : AbstractValidationAttribute
{
	public ValidateNonEmptyAttribute()
	{
	}

	public override IValidator Build()
	{
		IValidator validator = new NonEmptyValidator();
		
		ConfigureValidatorMessage(validator);
		
		return validator;
	}
}

i18n support

The default error messages are available in english, portuguese and dutch, using satellite assemblies. I considered an approach to have custom error messages and yet “localizable” ones, but gave up after 20 minutes. The best I could think of was using a special string that indicates an assembly should be loaded. Something like

public class Customer
{
	[ValidateNonEmpty(LocalizableMessage='name_is_required')]
	public string Name
	{
		..
	}
}

Javascript integration

The validator can declare that they support web validation. That means that a validator can configure a js library to perform the same validation it is supposed to perform. This is done using the IWebValidationGenerator, which exposes operation that most of the js validation libraries implement.

For example, here is a code snippet from the NonEmptyValidator:

public override bool SupportsWebValidation
{
	get { return true; }
}

public override void ApplyWebValidation(WebValidationConfiguration config, InputElementType inputType,
										IWebValidationGenerator generator, IDictionary attributes)
{
	generator.SetAsRequired(BuildErrorMessage());
}

It is up to the implementation of IWebValidationGenerator to attach the html to the element attributes. MonoRail has two implementations: for fValidate and for the Prototype Validation.

… and more!

Some validations may make sense for a situation, and be totally unnecessary in other. That’s why you can associate phases with validations:

[ValidateSameAs("Password", RunWhen=RunWhen.Insert)]
public string Confirmation
{
	get { return confirmation; }
	set { confirmation = value; }
}

The possible phases are: everytime, insert, update and custom.

When you use the runner, you can tell it to restrict the validation to a specific phase:

bool isValid = runner.IsValid(customer, RunWhen.Custom);

You can also define an execution order:

[ValidateNonEmpty(ExecutionOrder=1)]
[ValidateLength(3, 12, "Invalid password length", ExecutionOrder=2)]
public string Password
{
	get { return pwd; }
	set { pwd = value; }
}

A friendly name for a property may also be handy:

[ValidateNonEmpty(FriendlyName="CoResponsible user")]
public string CoResponsibleUserName
{
	get { return secondUser; }
	set { secondUser = value; }
}

The class diagram



If you want to give it a try, grab Castle’s source, or browse the source code.

Have fun!

Categories: Castle | Top Of Page | 22 Comments » |

22 Responses to “The Castle Validator component”

Claudio Maccari Says:

I translate the messages also in italian.
How can I send it to you?

hammett Says:

You can send a .patch file to the list, or through jira. See http://support.castleproject.org

Eugen Anghel Says:

Hi,
Me and a friend of mine are currently working on Contracts ( http://www.codeplex.com/contracts ) which uses DynamicProxy to automagically check the validators when a property or method is called.

Is there a possibility to include something like this in Castle ?

hammett Says:

I personally don’t like this approach, but if there’s a community claim to have something like that added to Castle, I’d definitely consider it.

goodwill Says:

It seems like I cannot find the LocalizableMessage property?

hammett Says:

Because there isn’t one. I couldn’t find a way to fully handle i18n yet, and I’m open for suggestions.

goodwill Says:

See if this looks ok for you:

[Resource(ResourceName='MyResourceLibName', AssemblyName='AssemblyName')]
public class MyClass
{
[FieldResource(FieldNameResourceKey='ResourceKey')]
[Validator(MessageResourceKey='ResourceKey')]
public int MyField
{

}
}

then in the message resource string:
en-US: $fieldName is required.
zh-tw: Ni Bi Shu Ten Shan $fieldName.
so the field name are isolated from the message, makes localization much easier (you dont have to create 20 full message for field required, instead just create field label for each field and then the message template)

I did something similar in fValidateLang indeed, I think that works.

hammett Says:

It works, but it’s too verbose. I’m considering approaches…

goodwill Says:

I suggest you put up a topic in devel group for everyone to discuss? Anyhow I think its quite important (at least for me) so I would like to have a workable approach soon whenever soonest possible.

hammett Says:

goodwill, you can start this topic on the devel list. I’d appreciate your use-cases and suggestions for it.

Anton Says:

if someone have been doing anything about i18n of validation, please, inform tell me. I chose to create a project with MonoRail and AR in language different then english, so soon I will need to supply site with localized error messages and I cant use the technique above, if it is not i18nable.

hammett Says:
MonoRail and Castle Validator « Random Code Says:

[...] to add validation to a web application I am building using MonoRail. A bit of research turned up a brilliant component created by Hammett that greatly simplifies adding client and server side validation in one [...]

Client & Server Side Validation in ASP.NET MVC | Emad Ibrahim Says:

[...] Hamilton Verissimo – link [...]

ASP.NET MVC Validation - The Definitive Guide (in my eyes) « {Programming} & Life Says:

[...] can be found in the Castle.Components.Validator namespace under “Attributes” and more information here. (I hadn’t used it till today). The best thing to do would be to download Emad’s sample [...]

Martijn Boland » Validation in ASP.NET MVC - part 2: custom server-side validation Says:

[...] series, I showed how you can perform basic server-side validation on your model with help of the Castle Validator component. To summarize this post: the controller validates an object that is decorated with validation [...]

Martijn Boland » Validation in ASP.NET MVC - part 1: basic server-side validation Says:

[...] Cuyahoga, we’re using the Castle Validator component to perform basic validation, mostly because we’re already using other components from the [...]

Martijn Boland » A new experiment Says:

[...] multi-part post about validation with Castle validators and ASP.NET [...]

rekna Says:

Would you consider supporting System.ComponentModel.DataAnnotations .Metadatatype attribute? It allows you to define the validation attributes on a class other than the entity class. Would be of great value for Linq to SQL projects as entity classes are auto generated. Or is it possible to subclass on of the classes of Castle Validator to allow getting custom attributes from a different source?

Example:
[Metadatatype(typeof(PersonMetaData))]
public class Person
{
public string Name {get;set;}
}

public class PersonMetaData
{
[ValidateLength(1,40)]
public string Name {get;set;}
}

hammett Says:

@rekna you should bring this suggestion to the castle devel mailing list. thanks

rekna Says:

I manage to get translated messages using this code:
if (model == null) return;
ResourceManager mgr = new ResourceManager(“Castle.Components.Validator.Messages”, Assembly.GetAssembly(typeof(Castle.Components.Validator.CachedValidationRegistry)));
var runner = new ValidatorRunner(new CachedValidationRegistry(mgr));
if (runner.IsValid(model) || !runner.HasErrors(model)) return;

var summary = runner.GetErrorSummary(model);
throw new RuleViolationException(summary);

The errors get translated correctly, but in the validation summary, the names of the properties are not mentioned.. I think it would be better to get ‘XXX’ is required instead of ‘This is a required field’?

rekna Says:

Added CachedMetadataValidationRegistry (for support of MetadataType) to support.castle.org

Leave a Reply