FluentValidation 0.2 Released

The second release of my validation library, FluentValidation, is now available for download.

Changes in this version:

  • Added Silverlight compatibility
  • Moved support for the CommonServiceLocator into a separate assembly
  • Adding additional interfaces for some of the validators (ILengthValidator, INotNullValidator)
  • AbstractValidator now implements IEnumerable<IRuleBuilder<T>>
  • Added ShouldHaveValidationError extension method for testing validators

Using ModelState with MvcContrib’s Fluent HTML Helpers

What is ModelState?

The ASP.NET MVC ModelState dictionary allows you to record validation errors which can then be displayed in your web page.

For example, imagine you add a textbox to a page using the MVC framework’s built-in HTML helpers, then this will render a standard text field:

Your name: <%= Html.TextBox("Name") %>

In your controller, if you add an error to the ModelState dictionary with the same name as the textbox, then the HTML helper will change the styling of the input field by adding a css class of “input-validation-error”.

public class HomeController : Controller {
   public ActionResult Index() {
       ModelState.AddModelError("Name", "Please enter a name");
       return View(new MyViewModel { Name = "" });
   }
}

Using the default ASP.NET MVC template, it will add a red border with a light pink background:

Textbox error

You can also display the actual validation errors by making use of the ValidationSummary helper:

<%= Html.ValidationSummary() %>
Enter your name: <%= Html.TextBox("Name") %>

Which will display something like this:

Validation Summary

ModelState with FluentHtml

By default, the Fluent HTML helpers in MvcContrib do not have support for ModelState. However, it is very easy to add support for this by writing a custom MemberBehaviour (I previously wrote about extending the HTML helpers with MemberBehaviors here)

Here is the implementation of the ModelStateMemberBehavior class:

public class ModelStateMemberBehavior : IMemberBehavior {
	private readonly ModelStateDictionary modelState;
 
	public ModelStateMemberBehavior(ModelStateDictionary modelState) {
		this.modelState = modelState;
	}
 
	public void Execute(IMemberElement element) {
		ModelState state;
		if (element.Builder.Attributes.ContainsKey("name")) {
			if (modelState.TryGetValue(element.Builder.Attributes["name"], out state)) {
				element.Builder.AddCssClass("input-validation-error");
			}
		}
	}
}

This class will check whether the name of the element being rendered is present in the specified ModelState dictionary. If so, it will add a css class of “input-validation-error” to the element being rendered.

Now we need to hook this into the HTML helpers. This can be done by implementing the IViewModelContainer interface on your base View Page:

public class MyBaseViewPage<T> : ViewPage<T>, IViewModelContainer<T> where T : class {
   private List<IMemberBehavior> memberBehaviors = new List<IMemberBehavior>();
 
   protected override void SetViewData(ViewDataDictionary viewData) {
      base.SetViewData(viewData);
      behaviors.Add(new ModelStateMemberBehavior(ViewData.ModelState));
   }
 
   public T ViewModel {
      get { return ViewData.Model; }
   }
 
   public IEnumerable<IMemberBehavior> MemberBehaviors {
	get { return memberBehaviors; }
   }
}

Now, so long as all your view pages inherit from MyBaseViewPage, any calls to the fluent HTML helpers will have support for ModelState:

Your name: <%= this.TextBox(model => model.Name) %>

Integrating FluentValidation with MvcContrib’s Fluent Html Helpers

A recent addition to the MvcContrib project are a set of HTML helpers that use a fluent interface written by Tim Scott.

One of the great things about these helpers is that you can change how the HTML is rendered by writing custom IMemberBehavior objects. For example, the helpers come with a set of attributes that you can use to decorate your model:

public class Customer {
   [MaxLength(50)]
   public string Name { get; set; }
}

Then, when you render your view, the HTML helper will automatically detect the presence of this attribute and render a “maxlength” attribute accordingly. For example, this textbox helper…

<%= this.TextBox(m => m.Customer.Name) %>

…would render this html:

<input type="text" maxlength="50" id="Customer_Name" name="Customer.Name" />

I wanted to take this a step further and integrate it with my validation library, so the HTML helpers will automatically pick up maxlength/required attributes from my validator classes.

Step 1: Custom Validator Class

The first stage was to create a metadata class to hold information about a validator.

public class PropertyModel {
	public int MaxLength { get; set; }
	public bool Required { get; set; }
	public PropertyInfo Property { get; private set; }
 
	public PropertyModel(PropertyInfo property) {
		Property = property;
	}
}

Next, I introduced a new interface, IPropertyDescriptor, that all my validator classes will implement. This interface defines the signature for a method that creates PropertyModel instances based on a PropertyInfo:

public interface IPropertyDescriptor {
	PropertyModel GetPropertyModel(PropertyInfo property);
}

Next, I added a custom base-class for all my validators which implements the above interface:

public abstract class Validator<T> : AbstractValidator<T>, IPropertyDescriptor {
	public PropertyModel GetPropertyModel(PropertyInfo property) {
		var model = new PropertyModel(property);
 
		var validators = this.OfType<IPropertyValidatorContainer<T>>().Where(x => x.Property == property).Select(x => x.Validator);
		foreach (var validator in validators) {
			if (HandleLengthValidator(validator, model)) continue;
			if (HandleRequiredValidator(validator, model)) continue;
		}
 
		return model;
	}
 
	private bool HandleLengthValidator(IPropertyValidator<T> validator, PropertyModel model) {
		var length = validator as ILengthValidator;
		if(length != null) {
			model.MaxLength = length.Max;
			return true;
		}
		return false;
	}
	private bool HandleRequiredValidator(IPropertyValidator<T> validator, PropertyModel model) {
		var required = validator as INotNullValidator;
		if(required != null) {
			model.Required = true;
			return true;
		}
		return false;
	}	
}

Essentially, the GetPropertyModel method iterates through all of the property validators to see if any required or max-length validators have been defined. If so, it records them in the PropertyModel object.

I can now define my validators as usual, but they now inherit from my new Validator<T> class, rather than AbstractValidator<T>.

public class CustomerValidator : Validator<Customer> {
   public CustomerValidator() {
     RuleFor(customer => customer.Name).Length(0, 50);
   }
}

Step 2: Custom Validator Factory

The next stage is to impelement a custom validator factory that can be used to instantiate validators. For this example, I’ll be using the Windsor IoC container.

Firstly, in my application startup routine I need to register all of my validators with Windsor:

var container = new WindsorContainer();
container.Register(AllTypes.Of(typeof(IValidator<>)).FromAssembly(typeof(CustomerValidator).Assembly).WithService.Base());

Next, I create a validator factory that uses Windsor (or more accurently, Microkernel) to create the validator instances.

public class ValidatorFactory : IValidatorFactory {
	private readonly IKernel container;
 
	public ValidatorFactory(IKernel container) {
		this.container = container;
	}
 
	public IValidator<T> GetValidator<T>() {
		return container.TryResolve<IValidator<T>>();
	}
 
	public IValidator GetValidator(Type type) {
		var genericType = typeof(IValidator<>).MakeGenericType(type);
		return (IValidator)container.TryResolve(genericType);
	}
}

Note that TryResolve is an extension method on IKernel that will attept to resolve a component and return null if it fails (by default, Windsor/Microkernel will throw an exception).

This validator factory can now be registered with the container:

container.Register(Component.For<IValidatorFactory>().ImplementedBy<ValidatorFactory>());

Step 3: The PropertyModelFactory

The next stage is to create a class that can be used to locate the correct validator from a PropertyInfo object (by using the validator factory) and return a corresponding PropertyModel.

public class PropertyModelFactory : IPropertyDescriptor {
   private IValidatorFactory validatorFactory;
 
   public PropertyModelFactory(IValidatorFactory validatorFactory) {
     this.validatorFactory = validatorFactory;
   }
 
  public PropertyModel GetPropertyModel(PropertyInfo property) {
     var descriptor = validatorFactory.GetValidator(property.ReflectedType) as IPropertyDescriptor;
     if(descriptor != null) {
        return descriptor.GetPropertyModel(property);
     }
     return null;
  }
}

Again, this needs to be registered with the container:

container.Register(Component.For<IPropertyDescriptor>().ImplementedBy<PropertyModelFactory>());

Step 4: Custom IMemberBehavior

Next, we need to create a custom IMemberBehavior that will make use of the PropertyModelFactory:

public class ValidatorMemberBehaviour : IMemberBehavior {
   private readonly IPropertyDescriptor descriptor;
 
   public ValidatorMemberBehaviour(IPropertyDescriptor descriptor) {
      this.descriptor = descriptor;
   }
 
   public void Execute(IMemberElement element) {
      if (element.ForMember == null) return;
 
      var property = element.ForMember.Member as PropertyInfo;
      if(property == null) return;
 
      var model = descriptor.GetPropertyModel(property);
      if (model == null) return;
 
      var maxLengthMethod = element.GetType().GetMethod("MaxLength");
 
      if(maxLengthMethod != null) {
         element.Builder.MergeAttribute("maxlength", model.MaxLength.ToString());				
      }
      if(model.Required) {
         element.Builder.AddCssClass("required");
      }
   }
}

MemberBehaviors are invoked when certain HTML helper objects are created, so this behaviour now needs to be registered with our ViewPage:

public class MyViewPage<T> : ModelViewPage<T> where T : class {
   public MyViewPage() 
     : base(new ValidatorMemberBehaviour(ServiceLocator.Resolve<IPropertyDescriptor>())) { }
}

Note that the ServicLocator static class is just a wrapper around Windsor.

So now the HTML Helpers will use my validator definitions to generate required/maxlength attributes. I think the extensibility of these helpers is incredibly powerful and I am planning on using them going forward in my next project.