I'm looking to implement custom client side validation in MVC4. I currently have it working well with the standard attributes, such as this in my model
public class UploadedFiles
{
[StringLength(255, ErrorMessage = "Path is too long.")]
[Required(ErrorMessage = "Path cannot be empty.")]
[ValidPath]
public string SourceDirectory { get; set; }
}
So StringLength and Required both are automatically translated into some JQuery client side validation. Currently "Valid Path" only works server side. The validation will always be required to be server side as only the server can validate if the path is valid, you couldn't do this client side.
The server side code looks like
public class ValidPathAttribute : ValidationAttribute, IClientValidatable
{
public string SourceDirectory;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string path = value.ToString();
string message = string.Empty;
var fileSystemSupport = new FileSystemSupport(Settings, new WrappedFileSystem(new FileSystem()));
if (fileSystemSupport.ValidateNetworkPath(path, out message))
{
return ValidationResult.Success;
}
return new ValidationResult(message);
}
}
And this works fine. Now I would like this to happen via an ajax call, step in "IClientValidatable" and "GetClientValidationRules". Following my book I have written
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule();
rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
rule.ValidationType = "validpath";
yield return rule;
}
I believe I now have to write some custom validation script code, the adapter (to identify the required metadata) and the validation rule itself (the validator, referenced by rule.ValidationType).
I don't think I need to write an adapter, I can just use
addBool - Create an adapter for a validator rule that is "on" or "off". The rule requires no additional parameters
So in UploadedFiles.js I now have
$.validator.unobtrusive.adapters.addBool("validpath", "required");
and in my view
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/Scripts/UploadedFiles.js")
}
I believe this is enough to hook everything up, but I now need to write the javascript validator. These live in the jQuery.validator object and can be added with $.validator.addMethod.
This is where I come a bit unstuck for several reasons:
1) Is this the correct way about things, if my validation lives server side then is this an ajax call? This will then need to be synchronous.
2) Is there an element of jQuery I should be reusing to do this? I had hoped given I've done the work server side I could just enable some magic to hook up the client side to it (much like the standard validation).
3) I would like this to be reusable, across various custom validation attributes. How can I make this generic?
Apologies if I've made a mountain out of a mole hill. Thanks for your time :)
Russ