Question

I'm pretty new to MVC and for a project I'd like to use the existing Register functionality from the Internet Application template, except move it into a jQuery Modal Dialog popup.

Here is the click event of my "new user" button, I got the idea from the answer on this question:

$("#new-user").click(function () {

   $("#dialog-modal").empty(); // clear it out first
   $("#dialog-modal").dialog({
      height: 600,
      width: 500,
      title: "New User",
      modal: true,
      open: function (event, ui) {
         $(this).load("@Url.Action("Register")");
      },
      buttons: {
         "Add New User": function (e) {
            var $this = this;
            var form = $('form', $this);

            $.post("Account/Register", JSON.stringify($(form).serializeObject()), 
               function () {
                  $($this).dialog("close");
            });
          }
      }
   });
});

The Url.Action method looks like this:

[HttpGet]
public ActionResult Register()
{
   return View("_Register");
}

And my _Register.cshtml View, which is basically a copy of the one from the template:

@model MyProject.Models.RegisterModel
@{
    Layout = null;
    ViewBag.Title = "Register";
}

<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
    <h2>Create a new account.</h2>
</hgroup>

@using (Html.BeginForm()) { 

    @Html.AntiForgeryToken()
    @Html.ValidationSummary()

    <fieldset>
        <legend>Registration Form</legend>
        <ol>
            <li>
                @Html.LabelFor(m => m.UserName)
                @Html.TextBoxFor(m => m.UserName)
            </li>
            <li>
                @Html.LabelFor(m => m.Password)
                @Html.PasswordFor(m => m.Password)
            </li>
            <li>
                @Html.LabelFor(m => m.ConfirmPassword)
                @Html.PasswordFor(m => m.ConfirmPassword)
            </li>
            <li>
                @Html.LabelFor(m => m.DisplayName)
                @Html.TextBoxFor(m => m.DisplayName)
            </li>
            <li>
                @Html.LabelFor(m => m.Email)
                @Html.TextBoxFor(m => m.Email)
            </li>
        </ol>
    </fieldset>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Now, when my "Add New User" button is clicked, you'll see I'm posting the form back to Account/Register which is the built in Action Method for the Internet Application template. That hasn't been changed at all and still is decorated with:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]

However, any time I click "Add New User" and the form is posted, I get the following 500 error message (seen in Fiddler):

The required anti-forgery form field "__RequestVerificationToken" is not present

I'm not sure why it isn't present because 1) my Register.cshtml View still contains @Html.AntiForgeryToken() and 2) if I step into that Javascript and look at the value of JSON.stringify($(form).serializeObject(), I see:

"{"__RequestVerificationToken":"X3APKURbjYGUYqY2qg1VdbYl50eVNzd7TJLYKCGC-awgkK7iNH_W6bVOw7C8zHDlygP0rVO2K4TLn5KE9CYsQN8VN1DbOOV0KzMGT7xso3o1","UserName":"theUserName","Password":"thePassword","ConfirmPassword":"thePassword","DisplayName":"theDisplayName","Email":"theEmail"}"

Can anyone see what I'm doing wrong?

Was it helpful?

Solution

Based on our chat

$(form).serialize() takes the form's controls and turns them in to a JavaScript object. then, but calling JSON.stringify you're wrapping the entire object in to a string. So now, a potential payload of the following:

{
  "__RequestVerificationToken": "X3APKURbjYGUYqY2qg1VdbYl50eVNzd7TJLYKCGC-awgkK7iNH_W6bVOw7C8zHDlygP0rVO2K4TLn5KE9CYsQN8VN1DbOOV0KzMGT7xso3o1",
  "UserName": "theUserName",
  "Password": "thePassword",
  "ConfirmPassword": "thePassword",
  "DisplayName": "theDisplayName",
  "Email": "theEmail"
}

Which would be received in as 6 separate parameters is now wrapped in one big string, which is only 1 parameter now.

Advice? Remove the JSON.stringify and just the AJAX call pass off as normal. Then ValidateAntiForgeryTokenAttribute can see the __RequestVerificationToken parameter come in instead of being masked as a string.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top