1

This is my server-side code that adds data to db:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "ID,UsersLanguage,OtherLanguage,Notes,Difficulty")] Word word)
    {
        if (ModelState.IsValid)
        {
            word.LastReviewed = DateTime.Now;
            word.NextReview = DateTime.Now;
            word.OwnerName = User.Identity.Name;
            word.ReviewInterval = 0;
            if (String.IsNullOrEmpty(word.OwnerName))
                return View(word);
            db.Words.Add(word);
            db.SaveChanges();

            return RedirectToAction("Create", new { addingSuccess = true });
        }

        return View(word);
    }

I want to add some data to database using javascript. So I wrote this:

$.ajax({
        type: "POST",
        url: "/Words/Create",
        data: { "UsersLanguage": questionToAdd, "OtherLanguage": answerToAdd }
    }).success(function (data) {
        console.log("Added");

        $(this).parent().fadeOut(1000);
    }).fail(function (data) {
        console.error("cannot add word");
    });

The problem is: this javascript code actually doesn't work. I'm getting error: "The required anti-forgery form field [...] is not present".

I think the reason is I have to send to server exactly the same object as server's "Word". OK, I could make variable in javascript that will look like "Word" class, but what if I once wanted to change "Word" class on my server? I would have to jump through all my scripts that send "Word" to server and change these js objects.

How to avoid that? How could I send some data without knowledge about how Word class is built? How can I send this "Word" to server without all data and make server to create missing variables?

Piotrek
  • 10,919
  • 18
  • 73
  • 136

3 Answers3

2

You need to pass the AntiForgeryToken, you can do this creating a form with the tolken and pass it in you data:

@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "__AjaxAntiForgeryForm" }))
{
    @Html.AntiForgeryToken()
}


<script type="text/javascript">

    $.ajax({
        type: "POST",
        url: "/Words/Create",
        data: { "UsersLanguage": questionToAdd,
                "OtherLanguage": answerToAdd,
                "__RequestVerificationToken": $('input[name="__RequestVerificationToken"]'.val()}
    }).success(function (data) {
        console.log("Added");

        $(this).parent().fadeOut(1000);
    }).fail(function (data) {
        console.error("cannot add word");
    });
</script>
Paulo Segundo
  • 448
  • 3
  • 6
0

I think I found the problem, I had to send something like AntiForgeryToken and I've done this basically the same way like in best answer here:

include antiforgerytoken in ajax post ASP.NET MVC

I don't know if it's the best way, but actually it works ^^

Community
  • 1
  • 1
Piotrek
  • 10,919
  • 18
  • 73
  • 136
0

You can not send an object without knowing how it is built. Why would you change class?. Generally, in any form creating object WORD in the MVC, should be built by @Html.EditorFor (word => word.Id) so how do you change the word class, you will also have to change all the forms. As for the problem: You can expand the object word, but if you not send new properties, will always null. As for the script: if your form is created using EditorFor (), input element in HTML always have id attribute equal named property. You can write a nice generic js function that will retrieve all the fields from the form and on the basis of selectors build parameter "data" and send to the Controllers.

devQwerty
  • 106
  • 1
  • 12