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 :)
This finds only one invalid field..
ReplyDelete