Try fast search NHibernate

22 October 2009

NHibernate.Validator : Extending Loquacious configuration

The needs to extend the configuration come when you having some custom and reusable validators.

For this post I will use a constraint to solve : if a string property is null or empty it is valid, but if it is not empty it must satisfy the minimal required number of characters.

Creating the Validator

The first step is create a class to hold the information needed during validation; in this case the minimal length required.

In NHV this class must inherits from System.Attribute and implements IRuleArgs.

[Serializable]
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class OptionMinLengthAttribute: Attribute, IRuleArgs
{
private string message = "the length must be greater than, or equal to, {MinLength}";

public OptionMinLengthAttribute(int minLength)
{
MinLength = minLength;
}

public int MinLength { get; set; }

#region IRuleArgs Members

public string Message
{
get { return message; }
set { message = value; }
}

#endregion
}

The Attribute is not completed because we need to specify the related validator but first we must implements it (with a test obviously):

[Serializable]
public class OptionMinLengthValidator : IInitializableValidator<OptionMinLengthAttribute>
{
public int MinLength { get; set; }

#region Implementation of IValidator

public void Initialize(OptionMinLengthAttribute parameters)
{
MinLength = parameters.MinLength;
}

public bool IsValid(object value, IConstraintValidatorContext context)
{
if (!ReferenceEquals(null, value) && !(value is string))
{
return false;
}
if (ReferenceEquals(null, value))
{
return true;
}
int realLength = ((string) value).Trim().Length;
return realLength == 0 || realLength >= MinLength;
}

#endregion
}

Note: the validator implements IInitializableValidator<OptionMinLengthAttribute> because we need a way to configure the variable MinLength in the validator-instance.

Now we can go back to the attribute and wire it to its related validator:

  [Serializable]
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
[ValidatorClass(typeof(OptionMinLengthValidator))]
public class OptionMinLengthAttribute : Attribute, IRuleArgs

Extending Loquacious

Our new validator is ready to be used as attribute (ValidatorMode.UseAttribute) or even using XML, but if we are using the Loquacious configuration, and we want reuse the definition, the next step is extend NHV’s definitions.

Considerations about our validator:
  1. It is working only for string so the candidate for the extension is IStringConstraints.
  2. It is chainable with others string constraints.
public static class StringConstraintsExtensions
{
public static IChainableConstraint<IStringConstraints> IfNotEmptyMinLength(this IStringConstraints definition,
int minLength)
{
var ruleArgs = new OptionMinLengthAttribute(minLength);
((IConstraints)definition).AddRuleArg(ruleArgs);
return new ChainableConstraint<IStringConstraints>(definition, ruleArgs);
}
}

What will happen will be:

ShowExtension

and we can chain the constraint with others as

public class AddressValidation: ValidationDef<Address>
{
public AddressValidation()
{
Define(a => a.AdditionalInfo).IfNotEmptyMinLength(5).And.MaxLength(80);
}
}
and reuse and reuse and reuse our new constraint.

3 comments:

  1. Thanks Fabio,

    I have been trying this for a couple of hours; I should have visited your blog sooner.

    Regards,

    Santos

    ReplyDelete
  2. A similar content was exposed in this post
    http://fabiomaulo.blogspot.com/2009/02/nhibernatevalidator-fluent-interface.html

    ReplyDelete
  3. Somehow I missed that post and I was missing the constraint extension.

    Thanks,

    Santos

    ReplyDelete