As announced in the this post NHibernate.Validator (NHV for friends) has its own embedded configuration based on fluent-interface (Loquacious for friends). This new feature will be general-available with the next version NHV1.2.0.
As test and because the new configuration is “Loquacious” enough I’m going to expose some examples without explication.
Example 1:
var configure = new FluentConfiguration();
configure.Register(
Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.Namespace.Equals("Company.Product.YourNamespace"))
.ValidationDefinitions())
.SetDefaultValidatorMode(ValidatorMode.UseExternal);
ve = new ValidatorEngine();
ve.Configure(configure);
Example 2:
var configure = new FluentConfiguration();
configure.Register(
Assembly.Load("Company.Product")
.ValidationDefinitions()
.Where(t => t.Namespace.Equals("Company.Product.YourNamespace"))
)
.SetDefaultValidatorMode(ValidatorMode.UseExternal)
.IntegrateWithNHibernate.ApplyingDDLConstraints().And.RegisteringListeners();
ve = new ValidatorEngine();
ve.Configure(configure);
The only thing you can’t configure, using FluentConfiguration, is the SharedEngineProvider because it is configurable only trough application config (by the way, from what I saw on the NET, an explication about what is the SharedEngineProvider is needed).
For the configuration, I have add two extensions methods, both named ValidationDefinitions(), to Assembly and to IEnumerable<System.Type>.
Example v1:
public AddressDef()
{
Define(x => x.Country)
.MaxLength(20).And
.NotNullable();
Define(x => x.floor)
.IncludedBetween(-2, 50).WithMessage("{floor.out.of.range}");
Define(x => x.Id)
.IncludedBetween(1, 2000);
Define(x => x.Line1)
.NotNullable();
Define(x => x.State)
.NotNullable().And
.MaxLength(3);
Define(x => x.Zip)
.NotNullable().And
.MaxLength(5).WithMessage("{long}").And
.MatchWith("[0-9]+");
Define(x => x.InternalValid)
.IsTrue();
}
What happen at design-time ? Some images are more clear than 100 words…
The first advantage of fluent-interface-configuration appear clear: a very little example is that you can’t define an integer property as not-nullable.
For instance validators here is the example using Attributes and its equivalent using fluent-configuration:
Example v2:
[AssertAnimal]
public class Suricato
{
}
public class SuricatoDef:ValidationDef<Suricato>
{
public SuricatoDef()
{
ValidateInstance.Using(new AssertAnimalAttribute());
}
}
Who know NHV know that we have some country-specific validators. Country-specific-validator is a clear example about how extend the framework.
The follow is the implementation of NHibernate.Validator.Specific.It (validators available for Italy):
public static class ItLoquaciousExtensions
{
public static IRuleArgsOptions IsCodiceFiscale(this IStringConstraints definition)
{
return ((IConstraints)definition).AddWithFinalRuleArgOptions(new CodiceFiscaleAttribute());
}
public static IRuleArgsOptions IsPartitaIva(this IStringConstraints definition)
{
return ((IConstraints)definition).AddWithFinalRuleArgOptions(new PartitaIvaAttribute());
}
public static IRuleArgsOptions IsPartitaIva(this IIntegerConstraints definition)
{
return ((IConstraints)definition).AddWithFinalRuleArgOptions(new PartitaIvaAttribute());
}
}
And obviously, at design-time, it appear like this:
Sometimes NHV is not so well know by NHibernate users (NHV has 5% of NH downloads). If you are using some other validation framework, in applications where you are using NHibernate, you should check if the validator are initializing collections and relations (proxy)… perhaps we should write something else about how NHV work together with NHibernate.