Required Validator For NHibernate Validators
I’ve recently switched from the Enterprise Library Validation Application Block to using NHibernate Validators. If you are not familiar with the NHibernate Validator project, they are part of the NHibernate Contrib project and offer Validation constraints, and validation runner, and tight integration with NHibernate (especially great if you use NHibernate to generate your DB).
One of the main reasons for my switch was integration with xVal (which EntLib Validation’s implementation prevents), and also to get some advanced but common validators like Email, Size, NotNullNotEmpty.
Anyway, I would recommend that you look at NHibernate Validator if you use NHibernate and are looking for a validation framework. However, this post is about writing a new validator that will integrate with NHibernate Validators – the Required validator.
Motivation for the Required Validator
Many of the varchar/nvarchar columns in my database are set to NotNull, and I also want to go a step further and make sure that they can’t be empty strings or just spaces.
There does exist a NotNull validator and a NotEmpty validator which work correctly on their own or combined, and there is a NotNullNotEmpty validator as well.
However, the NotNullNotEmpty validator only works on IEnumerable types, even though the NotNull and NotEmpty validator work on strings.
So What Can We Do?
First, and simplest, is to put both a NotNull and a NotEmpty validator on each string property. In my case, our team was already familiar with a required validator and I found they were confused when the NotNullNotEmpty validator didn’t combine the two.
Option 2 is to write your own validator, which I did with the Required validator.
Required Validator
In order to make a custom NHibernate Validtor with accompanying Attribute, you should write two classes.
The first is the validator class, which should implement IValidator (NHibernate.Validator.Engine.IValidator). This just defines one method, IsValid() which returns a bool. The whole implementation is as follows:
/// <summary>
/// Required Validator means the value can not be null or empty (or only spaces)
/// </summary>
public class RequiredValidator : IValidator
{
public bool IsValid(object value, IConstraintValidatorContext constraintValidatorContext)
{
if (value == null)
{
return false;
}
var check = value as string;
if (check != null)
{
return !string.Empty.Equals(check.Trim());
}
var ev = value as IEnumerable;
if (ev != null)
{
return ev.GetEnumerator().MoveNext();
}
return false;
}
}
Basically this first checks if the value is null – if it is we return that this object is not valid. After that we just copy the code from the NotEmpty validator and check to see if a trimmed version of the string is not equal to string.Empty. It also can check for empty Enumerables just like NotNullNotEmpty.
Required Attribute
The second class to write is an attribute which handles the parameters and message, and uses the ValidatorClass[] attribute to tell the validation runner which validator it executes.
[Serializable]
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
[ValidatorClass(typeof(RequiredValidator))]
public class RequiredAttribute : Attribute, IRuleArgs
{
public string Message
{
get { return _message; }
set { _message = value; }
}
private string _message = "{validator.notNullNotEmpty}"; //Use the not empty language by default
}
Usage
Of course you can use this just like any other NHibernate Validator and even side by side with existing validators:
[Length(50)]
[Required]
public virtual string FirstName { get; set; }
[Length(50)]
[Required]
public virtual string LastName { get; set; }
Integration with xVal
Integration with xVal just takes one more line inside the validation rules provider (see my post on using xVal with NHibernate Validator)
ruleEmitters.AddSingle<RequiredAttribute>(x=>new RequiredRule());
Conclusion
We now have a Required Validator that we can use in our project, and it even integrates with xVal. Now this was a really simple change, but I’ll write soon about some more complex custom validators which might prove helpful.