2

I have tried to use AJAX call in an MVC5 project as many similar examples on the web, but every time there is an error i.e. antiforgerytoken, 500, etc. I am looking at a proper AJAX call method with Controller Action method that has all the necessary properties and sending model data from View to Controller Action. Here are the methods I used:

View:

@using (Html.BeginForm("Insert", "Account", FormMethod.Post, new { id = "frmRegister" })) 
{
    @Html.AntiForgeryToken()
    //code omitted for brevity
}



<script>

    AddAntiForgeryToken = function (data) {
    data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
    return data;
    };

$('form').submit(function (event) {
        event.preventDefault();

        //var formdata = JSON.stringify(@Model); //NOT WORKING???
        var formdata = new FormData($('#frmRegister').get(0));
        //var token = $('[name=__RequestVerificationToken]').val(); //I also tried to use this instead of "AddAntiForgeryToken" method but I encounter another error

        $.ajax({
            type: "POST",
            url: "/Account/Insert",
            data: AddAntiForgeryToken({ model: formdata }),
            //data: { data: formdata, __RequestVerificationToken: token },
            //contentType: "application/json",
            processData: false,
            contentType: false,

            datatype: "json",
            success: function (data) {
                $('#result').html(data);
            }
        });

    });
</script>

Controller: Code cannot hit to this Action method due to antiforgerytoken or similar problem.

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public JsonResult Insert(RegisterViewModel model)
{
    try
    {
         //...
         //code omitted for brevity
    }
}

I just need a proper AJAX and Action methods that can be used for CRUD operations in MVC5. Any help would be appreciated.

UPDATE: Here is some points about which I need to be clarified:

1) We did not use "__RequestVerificationToken" and I am not sure if we send it to the Controller properly (it seems to be as cookie in the Request Headers of Firebug, but I am not sure if it is OK or not). Any idea?

2) Should I use var formdata = new FormData($('#frmRegister').get(0)); when I upload files?

3) Why do I have to avoid using processData and contentType in this scenario?

4) Is the Controller method and error part of the AJAX method are OK? Or is there any missing or extra part there?

Jack
  • 1
  • 21
  • 118
  • 236
  • Using `var formdata = new FormData($('#frmRegister').get(0));` will include the antiforgery token. All you need is `data: formdata,` although its not clear why your using `FormData` (are you uploading files as well?) –  Aug 17 '16 at 22:20

2 Answers2

5

If the model in your view is RegisterViewModel and you have generated the form controls correctly using the strongly typed HtmlHelper methods, then using either new FormData($('#frmRegister').get(0)) or $('#frmRegister').serialize() will correctly send the values of all form controls within the <form> tags, including the token, and it is not necessary to add the token again.

If your form does not include a file input, then the code should be

$('form').submit(function (event) {
    event.preventDefault();
    var formData = $('#frmRegister').serialize();
    $.ajax({
        type: "POST",
        url: '@Url.Action("Insert", "Account")', // do not hard code your url's
        data: formData,
        datatype: "json", // refer notes below
        success: function (data) {
            $('#result').html(data);
        }
    });
});

or more simply

$.post('@Url.Action("Insert", "Account")', $('#frmRegister').serialize(), function(data) {
    $('#result').html(data);
});

If you are uploading files, then you need you need to use FormData and the code needs to be (refer also this answer and

$('form').submit(function (event) {
    event.preventDefault();
    var formData = new FormData($('#frmRegister').get(0));
    $.ajax({
        type: "POST",
        url: '@Url.Action("Insert", "Account")',
        data: formData,
        processData: false,
        contentType: false,
        datatype: "json",  // refer notes below
        success: function (data) {
            $('#result').html(data);
        }
    });
});

Note that you must set both processData and contentType to false when using jQuery with FormData.

If you getting a 500(Internal Server Error), it almost always means that your controller method is throwing an exception. In your case, I suspect this is because your method is returning a partial view (as suggested by the $('#result').html(data); line of code in you success callback) but you have specified that the return type should be json (your use of the datatype: "json", option). Note that it is not necessary to specify the dataType option (the .ajax() method will work it out if its not specified)

If that is not the cause of the 500(Internal Server Error), then you need to debug your code to determine what is causing the expection. You can use your browser developer tools to assist that process. Open the Network tab, run the function, (the name of the function will be highlighted), click on it, and then inspect the Response. It will include the details of the expection that was thrown.

Community
  • 1
  • 1
  • Thank you very very much for your wonderful explanations. I think this topic should be divided into two parts as you did "with and without uploading files" and now I am entirely clarified with the help of your answers. On the other hand, I am sure that these answers will help many people who fed up with searching a proper solution regarding to AJAX call :) Regards... – Jack Aug 19 '16 at 12:33
  • As I have overwhelmed the problems regarding to using AJAX in MVC, I will proceed with AJAX call for all of the actions in my MVC project. Do you recommend to do so, or is there any point that I should be attention? – Jack Aug 19 '16 at 12:35
  • The only reason to use ajax is to stay on the same page. In many cases you will probably want to just make a normal submit and redirect to another view in the POST method (or return the view if `ModelState` is invalid). In your case, you appear to want to save something and then update the current page with some extra data, in which case, using ajax is appropriate. Its a common mistake by beginners to use ajax, and then in the success callback do a `location.href='....'` to redirect (which is pointless) –  Aug 19 '16 at 12:51
  • Ok, I understand the main points you emphasized in your last comment i.e. redirecting to another url in AJAX is meaningless :) Actually I have developed several MVC app by using normal submit and now I want to make some page responsive and feel the user the speed of my applications (when using AJAX operations seems to be much more faster and I also like to display alerts to the users about what's going on regarding to the last user operation. So, I will use AJAX in my application as long as not needing to redirect in it :) Thanks a lot again for these huge and useful information... – Jack Aug 19 '16 at 13:13
1

contentType should be application/x-www-form-urlencoded

Try this code

    <script>
$('form').submit(function (event) {
        event.preventDefault();

    $.ajax({
        method: "POST",
        url: "/Account/Insert",
        data: $(this).serialize(),
       contentType:"application/x-www-form-urlencoded",
        success: function (data) {
       $('#result').html(data);
        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.log(errorThrown);
        }
    });
});
    </script>
Joshua Leigh
  • 340
  • 1
  • 3
  • 8
  • "TypeError: Argument 1 of FormData.constructor does not implement interface HTMLFormElement." >>> var formData = new FormData($('#frmRegister')); – Jack Aug 17 '16 at 18:24
  • I have modified the code try this and let me know what happens. – Joshua Leigh Aug 18 '16 at 01:02
  • 1
    Wrong. `contentType` needs to be set to `false` in order for `FormData` to work (as OP has done) –  Aug 18 '16 at 02:00
  • @StephenMuecke Dear Stephen, why do not post an answer as an example of best AJAX call in MVC with the Controller method? Because you always give perfect answer and teach good approaches to many people :) I am waiting for your answer, thanks a lot... – Jack Aug 18 '16 at 07:39
  • @StephenMuecke You are a real magic! Thanks a lot again... I have added some points to the update part of my question. Could you please clarify me about these points? – Jack Aug 19 '16 at 06:09