skip to main | skip to sidebar

Monday, February 11, 2008

Extension method validators

I'm building an MVC Framework application at the moment and I wanted a simple, easy to grep way of validating fields passed back from forms. In MVC-land all the form variables are passed as parameters to the action method. Extension methods turned out to be a very neat solution for doing validation and data conversion. Here's an example:

[ControllerAction]
public void UpdateContact(
 int contactId,
 string name,
 string address1,
 string address2,
 string address3,
 string county,
 string postcode,
 string telephone,
 string email)
{
 try
 {
 name.Label("Name").IsRequired();
 address1.Label("Address 1").IsRequired();
 county.Label("County").IsRequired();
 postcode.Label("Postcode").IsRequired().IsPostcode();
 telephone.Label("Telephone").IsRequired().IsTelephoneNumber();
 email.Label("Email").IsRequired().IsEmail();
 }
 catch (ValidationException exception)
 {
 ContactViewData viewData = ContactViewData(contactId);
 viewData.ErrorMessage = exception.Message;
 RenderView("Contact", viewData);
 return;
 }
 // update the contact and render the view
}

As you can see we pass the contact's details from a form. In the try block the extension method validators are called. Any of them can raise a validation exception which is caught by the catch block and a view is rendered showing the validation error.

The 'Label' extension returns a ValidateField instance that can be consumed by any other validator, this is so that we can raise exceptions that can be displayed directly to the user:

public static ValidateField Label(this string value, string label)
{
 return new ValidateField { Value = value, Label = label };
}

The 'IsRequired' extension takes a ValidateField and checks that the value is not null or empty:

public static ValidateField IsRequired(this ValidateField validateField)
{
 if (string.IsNullOrEmpty(validateField.Value))
 {
 throw new ValidationException(string.Format("{0} is required", validateField.Label));
 }
 return validateField;
}

And finally the 'IsEmail' extension uses a Regex to validate the string value:

public static ValidateField IsEmail(this ValidateField validateField)
{
 // ignore is null or empty, use IsRequired in parrallel to check this if needed
 if (string.IsNullOrEmpty(validateField.Value)) return validateField;
 string patternLenient = @"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*";
 if (!Regex.Match(validateField.Value, patternLenient).Success)
 {
 throw new ValidationException(string.Format("{0} must be a valid email address", validateField.Label));
 }
 return validateField;
}

I'm finding extension methods a real boon for writing DSL-ish APIs. I'll leave the 'IsTelephone' and 'IsPostcode' exercises for your enjoyment :)

Posted by Mike Hadlow at 8:58 pm

1 comment:

Anonymous said...

This finds only one invalid field..

1:18 pm

Post a Comment

Subscribe to: Post Comments (Atom)
 

AltStyle によって変換されたページ (->オリジナル) /