http://fluentvalidation.codeplex.com/discussions/258348
So, I had to create my own remote validator extension to FluentValidation. For those who cannot wait for the official remote validation for fluent validation. Here's how I did it.
//Create a validator, that does nothing on the server side. public class RemoteValidator : PropertyValidator { public string Url { get; private set; } public string HttpMethod { get; private set; } public string AdditionalFields { get; private set; } public RemoteValidator(string errorMessage, string action, string controller, HttpVerbs HttpVerb = HttpVerbs.Get, string additionalFields = "") : base(errorMessage) { var httpContext = HttpContext.Current; if (httpContext == null) { var request = new HttpRequest("/", "http://ubasolutions.com", ""); var response = new HttpResponse(new StringWriter()); httpContext = new HttpContext(request, response); } var httpContextBase = new HttpContextWrapper(httpContext); var routeData = new RouteData(); var requestContext = new RequestContext(httpContextBase, routeData); var helper = new UrlHelper(requestContext); Url = helper.Action(action, controller); HttpMethod = HttpVerb.ToString(); AdditionalFields = additionalFields; } protected override bool IsValid(PropertyValidatorContext context) { //This is not a server side validation rule. So, should not effect at the server side. return true; } } //Create a MVC wrapper for the validator. public class RemoteFluentValidationPropertyValidator : FluentValidationPropertyValidator { private RemoteValidator RemoteValidator { get { return (RemoteValidator)Validator; } } public RemoteFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule propertyDescription, IPropertyValidator validator) : base(metadata, controllerContext, propertyDescription, validator) { ShouldValidate = false; } public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() { if (!ShouldGenerateClientSideRules()) yield break; var formatter = new MessageFormatter().AppendPropertyName(Rule.PropertyDescription); string message = formatter.BuildMessage(RemoteValidator.ErrorMessageSource.GetString()); //This is the rule that asp.net mvc 3, uses for Remote attribute. yield return new ModelClientValidationRemoteRule(message, RemoteValidator.Url, RemoteValidator.HttpMethod, RemoteValidator.AdditionalFields); } }
Thats all. Now you'll have to register the Validator inside the applicaition_start in the global.asax file.
//Note that I'm using NinjectValidatorFactory for injecting Fluent validation into the modelbinders. So, this configuration may differ a little on every system. FluentValidationModelValidationFactory validationFactory = (metadata, context, rule, validator) => new RemoteFluentValidationPropertyValidator(metadata, context, rule, validator); FluentValidationModelValidatorProvider.Configure(x => x.Add(typeof(RemoteValidator), validationFactory)); NinjectValidatorFactory ninjectValidatorFactory = new NinjectValidatorFactory(kernel); var validationProvider = new FluentValidationModelValidatorProvider(ninjectValidatorFactory); validationProvider.Add(typeof(RemoteValidator), validationFactory); ModelValidatorProviders.Providers.Add(validationProvider); DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false; kernel.Load<FluentValidatorModule>();
How to apply the validation Rule?
Ok, now we will be setting rules for validation.
RuleFor(x => x.UserName).NotEmpty().SetValidator(new RemoteValidator("user name already exists", "ValidateUserName", "Account", System.Web.Mvc.HttpVerbs.Post));
Well, that was quite simple wasn't it?
Here is the code for ValidateUserName Action inside Account controller
public ActionResult ValidateUserName(string username) { var user = UserRepository.FindSingleByUsername(username); if (user == null) return Json(true, JsonRequestBehavior.AllowGet); return Json("Username already exists", JsonRequestBehavior.AllowGet); }
Thats it folks. Your remote validation is ready to go.
N.B.
You can see that this is just a wrapper around Asp.net mvc's Remote Attribute, and works more or less on same way the Remote attribute would work.
Asp.net mvc 3 unobtrusive validation fires validation on every keyup event. So, I had to change jquery.validate.unobtrusive.js to fire validation only on blur events. I still could not find a reliable way to do this only on the elements with remote validation, since they(microsoft) are doing validation at the form level instead of element level. To be able to set individual settings, a massive rewrite of jquery.validate.unobtrusive.js may be required.
Update May 11, 2012
For all those looking for the change in the way unobtrusive validator works, I will point you to this stack overflow question: http://stackoverflow.com/questions/4798855/mvc-3-specifying-validation-trigger-for-remote-validation
I used the technique mentioned in this answer: http://stackoverflow.com/a/4836653