3

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

Russ Taylor
  • 360
  • 3
  • 10
  • Looks like you could use the built in `[Remote]` attribute. [How to: Implement Remote Validation in ASP.NET MVC](http://msdn.microsoft.com/en-us/library/gg508808(VS.98).aspx) –  Nov 19 '14 at 23:07

1 Answers1

5

MVC comes with RemoteAttribute which internally makes an ajax call to a controller method that returns a Json value indicating if validation succeeded or failed

public JsonResult IsValid(string SourceDirectory)
{
  if (someCondition) //test if the value of SourceDirectory is valid
  {
    return Json(true, JsonRequestBehavior.AllowGet); // indicates its valid
  }
  else
  {
    return Json(false, JsonRequestBehavior.AllowGet); // indicates its not valid
    // or return Json("A custom error message that overrides the default message defined in the attribute");
  }
}

and decorate your property with

[Remote("IsValid", "YourController", ErrorMessage = "The path is not valid")]
public string SourceDirectory { get; set; }

Note: The RemoteAttribute is only for client side (jquery unobtrusive validation) and you may still need additional server side validation.

Refer How to: Implement Remote Validation in ASP.NET MVC for a detailed example