NHibernate is for sure one of the prodigy child of the .NET open-source movement, yet there are some other great libraries and frameworks. One of them is NHibernate Validator which belongs to NHibernate Contrib project. What it does is to validate your domain entities that supposedly are being persisted using NHibernate, but it provides so much flexibility that you can validate almost every POCO class using attributes.

I’m using it in an ASP.NET MVC project, so first let’s see how to configure and make it work here.

I’m using the trunk build of the Castle and NH Contrib Projects. Things may work differently on other versions.

First thing you need to do is to initialize Validator’s engine. I’m using it on a web application so let’s initialize and use a shared engine. I’m also using the attribute based validation, but you can write the validation logic in your .hbm mapping files.

public class MvcApplication : System.Web.HttpApplication, IMvcApplication
{
    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
        CreateDependencyInjectionContainer();
        RegisterControllerFactory();
        RegisterSessionFactory();
        RegisterValidatorEngine();
    }

    private void RegisterValidatorEngine()
    {
        var config = new NHVConfigurationBase();

        config.Properties[Environment.ApplyToDDL] = "false";
        config.Properties[Environment.AutoregisterListeners] = "true";
        config.Properties[Environment.ValidatorMode] = "UseAttribute";
        config.Properties[Environment.SharedEngineClass] = typeof (ValidatorEngine).FullName;
        config.Mappings.Add(new MappingConfiguration("MyApp.Domain", null));

        Environment.SharedEngineProvider = new NHibernateSharedEngineProvider();
        Environment.SharedEngineProvider.GetEngine().Configure(config);

        ValidatorInitializer.Initialize(NHibernateConfig);
    }
}

…and that’s it. You can validate entities passed to your controller’s action by creating an extension method which simplifies things and automatically adds all the errors to the ModelState:

public static class ControllerExtensions
{
    /// <summary>
    /// Validates an entity
    /// </summary>
    public static void Validate(this Controller controller, IValidatable entity)
    {
        var engine = Environment.SharedEngineProvider.GetEngine();
        var errors = engine.Validate(entity);

        foreach (var error in errors)
        {
            controller.ModelState.AddModelError(error.PropertyName, error.Message);
        }
    }
}

Note that IValidatable is just a marker interface. To call this method and do the actual validation, you need to call the validate method:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Contact(ContactMessage msg)
{
    try
    {
        this.Validate(msg);

        if (ModelState.IsValid)
        {
            this.messengerService.SendMail(msg);
            return RedirectToAction("Index");
        }
    }
    catch (Exception ex)
    {
        ModelState.AddUnhandledError(ex);
    }

    return View(msg);
}

Easy, right? but it can even get easier! With the power of ASP.NET MVC ActionFilters we can automagically validate our parameters when the action is invoked:

/// <summary>
/// Automatically validates all the action
/// parameters of type IValidatable.
/// </summary>
public class AutoValidate : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var controller = filterContext.Controller as Controller;
        if(controller == null)
            return;

        foreach (var entity in GetEntitiesFromParameters(filterContext.ActionParameters))
        {
            controller.Validate(entity);
        }
    }

    private static IEnumerable<IValidatable> GetEntitiesFromParameters(IEnumerable<KeyValuePair<string, object>> dictionary)
    {
        var validatableParameters = new List<IValidatable>();

        foreach (var keyValue in dictionary)
        {
            if(keyValue.Value is IValidatable)
            {
                validatableParameters.Add((IValidatable)keyValue.Value);
            }
        }

        return validatableParameters;
    }
}

…and your action method looks as simple as this:

[AcceptVerbs(HttpVerbs.Post)]
[AutoValidate]
public ActionResult Contact(ContactMessage msg)
{
    if(ModelState.IsValid)
    {
        try
        {
            this.messengerService.SendMail(msg);
            return RedirectToAction("Index");
        }
        catch (Exception ex)
        {
            ModelState.AddUnhandledError(ex);
        }
    }

    return View(msg);
}

Have fun validating!