Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC3 Controller null parameter using json.stringify

I have a very simple controller method that accepts a Guid parameter, like so

public JsonResult GetById(Guid id)
{
    var results = from a in repository.AsQueryable<Department>()
                  where a.Id == id
                  orderby a.Name
                  select new { id = a.Id, name = a.Name };

    return Json(results, JsonRequestBehavior.AllowGet);
}

The parameter is always null when using JSON.stringify() in Chrome, IE and Firefox. Example...

$(document).ready(function () {
    var o = new Object();
    o.id = 'C21803C3-1385-462E-ACEA-AFA1E554C635';

    $.getJSON('@Url.Action("GetById", "User")', JSON.stringify(o), function () {
        alert('Completed');
    });
});

This has worked before in ASP.NET 4.0. What is odd is that the following DOES work.

$(document).ready(function () {
    $.getJSON('@Url.Action("GetById", "User")', { "id": "C21803C3-1385-462E-ACEA-AFA1E554C635" }, function () {
        alert('Completed');
    })
    .error(function (a, b, c) {
        alert(a.responseText); alert(b); alert(c);
    });
});

If I run...

$(document).ready(function () {
    var o = new Object();
    o.id = 'C21803C3-1385-462E-ACEA-AFA1E554C635';

    alert(JSON.stringify(o));
});

I get

{"id":"C21803C3-1385-462E-ACEA-AFA1E554C635"}

displayed, proper JSON. And if I run

$(document).ready(function () {
    var o = new Object();
    o.id = 'C21803C3-1385-462E-ACEA-AFA1E554C635';

    var json_text = JSON.stringify(o, null, 2);
    alert(json_text);

    var your_object = JSON.parse(json_text);

    alert(your_object.id);
});

If get

C21803C3-1385-462E-ACEA-AFA1E554C635

Additional notes,

I have tried this as an ajax post, same issue.I tried a limited post, but see below for a full work though.

I have tried to insert white space, as JSON.stringify(o, null, 2), same issue.

Using jquery-1.7.1.min.js, jquery-ui-1.8.16.custom.min.js, jquery.unobtrusive-ajax.js, jquery.validate.min.js, and jquery.validate.unobtrusive.min.js. The only other JS is to open forms in a jquery dialog if javascript is enabled and to create a clickable table.

$.ajaxSetup({ cache: false });

$(document).ready(function () {
    $(".openDialog").live("click", function (e) {
        e.preventDefault();

        $("<div></div>")
                .addClass("dialog")
                .attr("id", $(this).attr("data-dialog-id"))
                .appendTo("body")
                .dialog({
                    title: $(this).attr("data-dialog-title"),
                    close: function () { $(this).remove() },
                    modal: true
                })
                .load(this.href);
    });

    $(".close").live("click", function (e) {
        e.preventDefault();
        $(this).closest(".dialog").dialog("close");
    });



    var clickableTable = $('tr[data-tr-clickable-url]');

    if (clickableTable.length > 0) {
        clickableTable.addClass('clickable')   // Add the clickable class for mouse over
            .click(function () {
                window.location.href = $(this).attr('data-tr-clickable-url');
            });

        // Remove the last child, containing anchors to actions, from each row, including the header.
        $('tr :last-child').remove();
    }
});

UPDATE

The following works:

var o = new Object();
o.Id = 'C21803C3-1385-462E-ACEA-AFA1E554C635';

$.ajax({
    url: '@Url.Action("GetById", "User")',
    type: "POST",
    data: JSON.stringify(o),
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function () {
        alert('completed');
    }
});

The following does NOT work:

var o = new Object();
o.Id = 'C21803C3-1385-462E-ACEA-AFA1E554C635';

$.ajax({
    url: '@Url.Action("GetById", "User")',
    data: JSON.stringify(o),
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function () {
        alert('completed');
    }
});

Thus, removing POST as type causes the call to fail. Note that according to jQuery documentation, $.getJSON is equivalent to

$.ajax({
  url: url,
  dataType: 'json',
  data: data,
  success: callback
});

Notice, there is not a type defined. Not sure where exactly the error lies, but something is getting missed somewhere. Especially since passing in an actual JSON object on $.getJSON actually works.

like image 957
user1097974 Avatar asked Mar 15 '26 13:03

user1097974


1 Answers

I think that the problem is with the default model binder that dosen't accept GET methods passing JSON thru QueryString.

For example:

         $.getJSON('/', JSON.stringify({id:"test"}));

Will generate this GET request GET http://localhost?{%22id%22:%22test%22} HTTP/1.1

Here it seems like the modelbinder have problem to bind it. Without stringify

         $.getJSON('/', {id:"test"});

will generate this GET request GET http://localhost/?id=test HTTP/1.1

And its possible for MVC to bind it, couse its the same as sending it in QueryString. Using POST insted will work fine.

But you can also implement a custom binder, maybe something like this (I don't know exactly how to do this)

public class Binder : IModelBinder
{
    #region IModelBinder Members

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var query = controllerContext.HttpContext.Request.Url.Query;
        var json = System.Web.HttpUtility.UrlDecode(query.Remove(0,1));
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        return serializer.Deserialize(json, bindingContext.ModelType.GetType());
    }

    #endregion
}
like image 79
Simon Edström Avatar answered Mar 18 '26 04:03

Simon Edström