Search code examples
jqueryajaxjsonasp.net-mvc-3csrf

Posting a JSON model to ASP.Net MVC3 with Anti-forgery token


So, I've been banging my head against the wall with this, and I can't find any good sources for this. Maybe I'm forgetting how the model binding stuff works in MVC3, but here's what I'm trying to do: I have some an editor bound up with Knockout to handle editing of a model. There's not much to the model:

public class SetupTemplate
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Template { get; set; }
} 

The signature of the action i'm trying to call is:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UpdateTemplate(SetupTemplate template)

From another question on here, I picked up this rather helpful snippet to get the anti-forgery token:

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

Which all comes together with me trying to post an update via ajax:

payload = window.addAntiForgeryToken(ko.mapping.toJS(self.data));
$.ajax({
    type: "post",
    url: endpoint,
    data: payload,
    success: function(data) {
        //Handle success
    }});

Which results in this in the form data section of the Chrome developer tools

Id:1
Name:Greeting
Template: [Template Text]
__RequestVerificationToken: [The really long anti-forgery token]

The antiforgery token is picked up, but my model is null. Most examples I've seen of this just use a single parameter passed along, and not a model.

I'm sure I'm missing something obvious, any insights on what it could be?

EDIT: In response to @Mark, changing the call to this:

$.ajax({
type: "post",
dataType: "json",
contentType: 'application/json',
url: endpoint,
data: JSON.stringify(payload),
success: function(data) {
    //Do some stuff
}});

Results in a request payload of this:

{"Id":1,"Name":"Greeting","Template":"...","__RequestVerificationToken":"..."}:

And the server not picking up the anti-forgery token. This was tried both with and without the contentType parameters to $.ajax().


Solution

  • @Mark gets credit for leading me down the right path for this, and pointing me at some links that now let me handle the anti forgery token rather transparently. However, what solved the issue was changing:

    public ActionResult UpdateTemplate(SetupTemplate template)
    

    to:

    public ActionResult UpdateTemplate(SetupTemplate model)
    

    And now it's properly filling in the values. I'd really like to know why that fixed it, but for now, it works.