ASP.NET MVC RemoteAttribute validation not working - Action not being executed
Asked Answered
H

5

5

I've been pulling my hair out trying to figure out why ValidationController actions are not being triggered.

I have settings enabled in project-wide web.config:

<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />

I have the following controller:

[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public class ValidationController : Controller
{
    private readonly IUserRepository userRepository;

    public ValidationController(IUserRepository userRepository)
    {
        this.userRepository = userRepository;
    }

    public JsonResult IsUserNameAvailable(string username)
    {
        User user = userRepository.Get(u => u.UserName == username);

        if (user == null) return Json(true, JsonRequestBehavior.AllowGet);
        else return Json(false, JsonRequestBehavior.AllowGet);
    }
}

and the following viewmodel:

    [Required(ErrorMessage = "Required *")]
    [StringLength(50, MinimumLength = 4, ErrorMessage = "Please keep the username between four and twenty character.")]
    [Remote("IsUserNameAvailable", "Validation", ErrorMessage = "A user with this username already exists.")]
    [Display(Name = "Username")]
    public string UserName { get; set; }

And I have the following field in my form:

<form id="registerForm">
     ...
     @Html.ValidationMessageFor(m => m.UserName)
     @Html.TextBoxFor(m => m.UserName)
     @Html.LabelFor(m => m.UserName)
</form>

I do ajax form submission and already have server-side validation working perfectly:

$.post("/Account/Register", $('#registerForm').serialize(), function(){
   updateFormWithServerGeneratedErrors();
})

Although the server generated the correct input tag for my field:

<input ... data-val-remote-url="/Validation/IsUserNameAvailable" data-val-remote-additionalfields="*.UserName" data-val-remote="A user with this username already exists." ... >

I can manually hit my action by typing into the url: "/Validation/IsUserNameAvailable?username=SomeName" but Fiddler is NOT showing any requests being made to this url on keypresses or focus changes.

According to this tutorial I don't need to write any javascript to get this working. And yes, I have jquery.validate.js and jquery.validate.unobtrusive.js scripts already loaded by the time I start tinkering with the form.

What is the problem here?

Handal answered 26/12, 2012 at 19:18 Comment(1)
Similar question is another page: https://mcmap.net/q/1322349/-mvc5-viewmodel-validation-remoteSprinkler
H
5

Ok I found my answer.

To quote Darin Dimitrov here:

"Unobtrusive validation doesn't work out-of-the-box with dynamically added elements to the DOM - such as for example sending an AJAX request to the server which returns a partial view and this partial view is then injected into the DOM.

In order to make it work you need to register those newly added elements with the unobtrusive validation framework. To do this you need to call the $.validator.unobtrusive.parse on the newly added elements. You should put this code inside the AJAX success handler that is injecting the partial into your DOM."

The framework calls this method one time on page load, the problem in my scenario was that the form itself was a jquery dialog and so even the initial load was "dynamic". I had to register the form elements with the unobtrusive framework on dialog load:

$.validator.unobtrusive.parse('#registerForm');  

My ajax calls would also return and replace the form like so if it did not validate on the server-side:

registerDialog.empty().html(result.viewResult);

so I had to call parse() on the success callback as well to make sure validation continues to work after an ajax submit.

Handal answered 6/1, 2013 at 18:5 Comment(1)
what is success callback?Mosa
E
2

You need to change your JsonResult method parameter name from

public JsonResult IsUserNameAvailable(string username)

to

public JsonResult IsUserNameAvailable(string UserName)

it should be same as property name its case-sensitive.

Entrench answered 1/6, 2016 at 13:52 Comment(0)
V
1

The problem why validation function is not being fired is that this code

public JsonResult IsUserNameAvailable(string username)
{
    User user = userRepository.Get(u => u.UserName == username);

    if (user == null) return Json(true, JsonRequestBehavior.AllowGet);
    else return Json(false, JsonRequestBehavior.AllowGet);
}

should be added to the AccountController, not the ValidationController. Remove ValidationController class and add the IsUserNameAvailable method to your AccountController class.

Also change the line in the model, it should be something like this

[System.Web.Mvc.Remote("IsUserNameAvailable", "Account")]

That will solve the issue.

Volcano answered 30/12, 2012 at 3:56 Comment(7)
Thanks but this made no difference.Handal
I added my viewmodel to OP showing the route, which I can hit manually. I changed this to "Account" obviously when trying your solution.Handal
I already had using Remote = System.Web.Mvc.RemoteAttribute; in my header but I tried to do it explicitly like you say but still nothing. Fiddler shows no calls to the route. Do you know of any particular line in the js files that I should break on in firefox to see if it gets called. I have jquery, jquery.unobtrusive-ajax, jquery.validate, and jquery.validate.unobtrusive loaded in that order as described here: #11327292Handal
I haven't noticed you do ajax submission, you need to do something like this: if ($('#registerForm').valid()) {($.post("/Account/Register", $('#registerForm').serialize(), function(){ updateFormWithServerGeneratedErrors(); })}Volcano
hmm, not sure how that will help since I'm trying to trigger validation naturally on keypresses or focus losses. That ajax submission occurs only onclick of the submit button so that seems unrelated to "live" validation. I actually am not getting "live" validation on any of my inputs, not just the one concerning the Remote call. Upvoting your efforts for now, thanks.Handal
Just to discard other issues, what happens when you call $('#registerForm').valid()? Does it fire validation?Volcano
if I run $('#registerForm').valid() from the Firefox/Firebug Console, the form does not validate. In general I'm having difficulty getting unobtrusive validation in the form for all fields not just the remote one. As I mentioned according to the Microsoft tutorial I thought I didn't need to write any javascript to get this working. Do I need to define client side rules?Handal
S
0

I had kind of the same issue. Simply change this:

public JsonResult IsUserNameAvailable(string username)
{
    User user = userRepository.Get(u => u.UserName == username);

    if (user == null) return Json(true, JsonRequestBehavior.AllowGet);
    else return Json(false, JsonRequestBehavior.AllowGet);
}

to:

public JsonResult IsUserNameAvailable(string Username)
{
    User user = userRepository.Get(u => u.UserName == Username);
    if (user == null) 
    {
        return Json(true, JsonRequestBehavior.AllowGet);
    }
    return Json(false, JsonRequestBehavior.AllowGet);       
}

username to UserName which is your

public string UserName { get; set; }

I think it's case sensitive.

Hope it will help :)

Selfassertion answered 19/3, 2014 at 15:41 Comment(0)
C
-1

It seems you forget to specify the binding Action for the form. I tried this below code and it works

<form id="registerForm" action="Controller/Action">
     @Html.ValidationMessageFor(m => m.UserName)
     @Html.TextBoxFor(m => m.UserName)
     @Html.LabelFor(m => m.UserName)
</form>

or simply:

@using(Html.BeginForm()) {
     @Html.ValidationMessageFor(m => m.UserName)
     @Html.TextBoxFor(m => m.UserName)
     @Html.LabelFor(m => m.UserName)
}
Cq answered 3/1, 2013 at 3:29 Comment(1)
Thanks for the comment. I used @using (Html.BeginForm("JsonRegister", "Account", FormMethod.Post, new { id = "registerForm", class = "popupForm" })) { //the form } but it did not make a different. The reason being is that I am making an Ajax call to my controller so I don't need the action attribute.Handal

© 2022 - 2024 — McMap. All rights reserved.