When reviewing the wireframes and requirements for a new project I am about to work on, it quickly became clear validation (data and business rules) would have to be implemented differently than previous web based projects I've worked on.
Typical validation, especially for a web application, means you can't submit (POST) your changes unless all is well on the page - in other words you can't move to another page / screen until there are no validation errors. ASP.Net's validation does this out of the box - any validation errors, the POST isn't performed. Assuming here you're using Client side validation which will be necessary for this new project as the validation errors still need to be displayed on screen (so POSTing to the server to determine the validation errors won't make sense).
This project will be different:
- Users need to know about the validation errors, however it shouldn't stop them moving through out the application to fill out details on other pages.
- The validation errors need to be shown on screen.
- The validation errors will remove the ability to perform a commit of all the data collected (in this particular project, the commit is to a legacy banking system via web services). Which means the validation rules will be used in multiple parts of the application (the page were the data is collected, and a final commit page) - so the validation rules need to be centralized (because I don't want to repeat them)
So, using MVC, and with client side validation enabled (meaning the JQuery Validation plug-in will be used), The solution to these requirements were:
- After a while searching the web, I found that adding class="cancel" to the submit button, means the submit will still be performed (which is good, so we don't lose the data even if it is invalid) - and when the user returns, it will be loaded as is. More details can be found here (specifically 'Skipping validation on submit').
- Invoking the validation on the page being loaded can be performed by doing the following (i.e. perform the validation for everything within the form element):
$(document).ready(function () {
$('form').validate();
$('form').valid();
});
3. And finally the centralization of the validation / business rules. Because I don't want to 'embed' the validation in the view model for the page because I want re-use, I'm going to centralize on the domain (I'm going to use the Validation block in Enterprise Library). However, because these rules will be on the server, and I'm using Client side validation, the Remote attribute will allow the rules to be invoked via AJAX - e.g.
[Remote("ValidateAge", "Applicant", ErrorMessage = "Age is invalid")]
This results in the following attributes being added to the text input element (i.e. using Razor to create the textbox via Html.TextBoxFor(x => x.Age) )
<input data-val="true" data-val-remote="Age is invalid" data-val-remote-additionalfields="*.Age" data-val-remote-url="/Applicant/ValidateAge" id="Age" name="Age" type="text" class="input-validation-error">
So after every change in the texbox Applicant/ValidateAge will be called (data-val-remote-url), which means the Age validation logic can be invoked on the server. This same validation logic can be invoked again when needed on additional pages (e.g. when determining if the commit call to the banking system can be made).