1

I was trying to validate the user name through remote validation in client side and it's working fine in while adding the duplicate field in create Module but now it is not allowing me to edit the record using same name it's showing me the same error which I defined for create. I tried all the possible ways but not succeeded please help me. I have followed these link but it's not working in either way.

http://stackoverflow.com/questions/4778151/asp-net-mvc-3-remote-validation-to-allow-original-value http://stackoverflow.com/questions/6407096/asp-net-mvc-3-remote-attribute-passing-3-fields

here is my code what i have tried so far .please help experts.

[Required]
        [Remote("IsUserAvailable", "User", HttpMethod = "Post", ErrorMessage = "User already exist.", AdditionalFields = "InitialUserName")]
        [RegularExpression(@"^(?![\W_]+$)(?!\d+$)[a-zA-Z0-9 ]+$", ErrorMessage = "Invalid UserName ")]
 public string UserName { get; set; }


[HttpPost]
    public JsonResult IsUserAvailable([Bind(Prefix = "User.UserName")]string UserName, string initialUserName)
    {

        var result = uDbContext.Users.FirstOrDefault(a => a.UserName == UserName);
        if (result == null)
        {
            return Json(true, JsonRequestBehavior.AllowGet);
        }
        return Json(JsonRequestBehavior.AllowGet);
    }


@model User.ViewModel.ViewModelUser
@using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()
        @Html.ValidationSummary(true)
        @Html.HiddenFor(m => m.User.UserId)



                @Html.LabelFor(m.User.UserName)


               @Html.TextBoxFor(m => m.User.UserName)
                @Html.ValidationMessageFor(m.User.UserName)
                @Html.Hidden("initialUserName", Model.User)
            </div>
        </div>
}

Please help experts to complete my assignment.

3 Answers3

5

User appears to be a complex object so

@Html.Hidden("initialUserName", Model.User)

is likely to generate something like

<input type="hidden" name="initialUserName" value="YourAssemly.User" ... />

which is not going to help with validation.

You could ignore the validation by sending back the original name using

@Html.Hidden("InitialUserName", Model.User.UserName)
@Html.Hidden("User.InitialUserName", Model.User.UserName)

and then compare the values in the controller using

public JsonResult IsUserAvailable([Bind(Prefix = "User.UserName")]string UserName, string initialUserName)
public JsonResult IsUserAvailable([Bind(Prefix = "User.UserName")]string UserName, [Bind(Prefix = "User.InitialUserName")]string initialUserName)
{
  if (UserName == initialUserName)
  {
    // Nothing has changed so signal its valid
    return Json(true, JsonRequestBehavior.AllowGet);
  }
  // Check if the user name already exists
  var result = uDbContext.Users.FirstOrDefault(a => a.UserName == UserName);
  return Json(result == null, JsonRequestBehavior.AllowGet);
}

Side note: jquery remote validation is a GET call so the [HttpPost] attribute is not necessary

Edit

After debugging both the jquery-validate.js and jquery-validate-unobtrusive.js files, it turns out that the name attribute of any AdditionalFields must include the same prefix as the property being validated, and that the [Bind(Prefix="..")] attribute is then also required on those parameters in the method (refer amendments above)

An alternative might to create a simple class to post back to, for example

public class ValidateUserNameVM
{
  public string UserName { get; set; }
  public string InitialUserName { get; set; }
}

and

public JsonResult IsUserAvailable([Bind(Prefix = "User")]ValidateUserNameVM model)
{
  if (model.UserName == model.InitialUserName)
  ....
  • still the same error for edit it is not allowing me to edit the record –  Jan 30 '15 at 08:45
  • Then there is something else going on. And what do you mean its _not allowing me to edit the record_? A remote attribute will only give you an error message if it fails validation - it does not prevent you from editing it –  Jan 30 '15 at 08:53
  • And have you checked that values of `UserName` and `InitialUserName` are correct and as expected? –  Jan 30 '15 at 09:01
  • i am getting the value for userName = steve and initialUserName = null, and while editing it is simply giving me the validation error message User already Exists. –  Jan 30 '15 at 09:25
  • Check the html generated by the `@Html.Hidden("initialUserName", Model.User.UserName)` If the initial user name is "steve" then it should be `` which should post back. If that's OK, change it to `TextBoxFor()` to test if that works. –  Jan 30 '15 at 09:32
  • Strange, it should be posting back "steve" for both parameters. I know there are some bugs using `AdditionalFields` (I have reported 2 of them myself [here](http://stackoverflow.com/questions/26308852/mvc-remote-validation-with-additional-bool-fields/26309626#26309626) and [here](http://stackoverflow.com/questions/27513472/remote-validation-for-list-of-models/27517407#27517407)) although your code (with my changes) looks OK. I'll test this myself a little later. –  Jan 30 '15 at 09:53
  • @Miranda, After a bit of debugging, I found the solution and have updated my answer. I don't think its very intuitive to have to do this (and was not able to find any documentation on it), but at the same its not really a bug –  Jan 31 '15 at 00:11
  • Thank you So much Sir for your Efforts and Time. its working like a charm. –  Feb 02 '15 at 12:01
0

Your validation function is incomplete. Put a [Required] attribute on the UserName property of your model and try this:

public JsonResult IsUserAvailable(string userName, string initialUserName)
{
   if (userName.Trim().ToLower() != (initialUserName ?? "").Trim().ToLower())
   {
       var result = YourMethodToCheckTheDatabaseForUsernameIsAvailable(userName);
       return Json(result, JsonRequestBehavior.AllowGet);
   }
   return Json(true, JsonRequestBehavior.AllowGet);
}
joelmdev
  • 11,083
  • 10
  • 65
  • 89
  • Thankyou for your quick response but i am getting an error on this piece of code .... if(userName.Trim().ToLower() != initialUserName.Trim().ToLower()) –  Jan 29 '15 at 16:01
  • Without knowing the error I can only guess... is initialUserName null? – joelmdev Jan 29 '15 at 16:03
  • yeah the error is Object reference not set to an instance of an object. and i am getting null value –  Jan 29 '15 at 16:14
  • Thank you for you attention @joelmdev but now its different error operator ?? can not be applied on opearands bool and string . –  Jan 29 '15 at 16:20
  • @Miranda edited again, and this time I actually checked validity with VS. You should understand that the last error was a precedence issue, pretty easy to debug. – joelmdev Jan 29 '15 at 16:25
  • yeah sorry but i am still getting the same error and null values in both field, should i have to add this piece of code ... public JsonResult IsUserAvailable([Bind(Prefix = "User.UserName")]string userName, string initialUserName). after implementing this i am getting the value for userName other wise it is null –  Jan 29 '15 at 16:31
  • @ joelmdev i have updated my Question have a look and please suggest. right now i am not using viewModel. –  Jan 29 '15 at 16:46
0

For Who Get Null in the second paramter this simple idea could help

public JsonResult IsUserNameAvailable(string Name, string EditNameIssue)
        {//it will return true if match found elese it will return false. so i add !
            if (Name == EditNameIssue)
            {
                return Json(true, JsonRequestBehavior.AllowGet);
            }
            else
            {
                return Json(!db.Employees.Any(e => e.Name == Name), JsonRequestBehavior.AllowGet);
            }
        }

Go to The Class and add string EditNameIssue to the class so it could be sent to the controller

[MetadataType(typeof(EmployeeMetaData))]
    public partial class Employee
    {

        public string EditNameIssue { get; set; }
    }

And Edit the Remote attribute to send this addtional property

[Remote("IsUserNameAvailable","Employees",ErrorMessage ="User Name Already Taken",AdditionalFields = "EditNameIssue")]
        public string Name { get; set; }

This Logic may help if you add a name to edit textbox that is already taken

public JsonResult IsUserNameAvailable(string Name, string EditNameIssue)
    {//it will return true if match found elese it will return false. so i add !
        //Edit Request  
        if (Name == EditNameIssue)
        {
            //this mean he didn't change the name
            return Json(true, JsonRequestBehavior.AllowGet);
        }
        else if (Name != EditNameIssue)
        {
            //if he change the name in the edit go and check if the new name exist 
            //note if he modify and reenter it origin name it will be also erro he has to reload
            return Json(!db.Employees.Any(e => e.Name == Name), JsonRequestBehavior.AllowGet);
        }
        else if (string.IsNullOrEmpty(EditNameIssue))
        {//this mean you came from create request as there is no EditNameIssue in this view

            return Json(!db.Employees.Any(e => e.Name == Name), JsonRequestBehavior.AllowGet);

        }
        else
        {//just for the completeness
            return Json(false, JsonRequestBehavior.AllowGet);
        }


    }
Mohamed Fathallah
  • 1,274
  • 1
  • 15
  • 17