3

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.

user1097974
  • 53
  • 2
  • 6
  • 3
    Try to NOT stringify it, just: var o = { id : 'C21803C3-1385-462E-ACEA-AFA1E554C635'}; – Simon Edström Feb 06 '12 at 15:26
  • As suspected, this does work. It seems to be limited to JSON.stringify(). – user1097974 Feb 06 '12 at 15:50
  • I hade the same problem, but I was using jQuery.post(). I deleted my other answer then you pointed out that you hade to escape all characters. What I can see jQuery is doing it for you. Example: { id : "hello", input : "id=test" } will be transformed into this HTTP request: id=hello&input=id%3Dtest – Simon Edström Feb 06 '12 at 16:09
  • $.getJSON('/', {o:"test"}); = GET http://localhost:55332/?o=test HTTP/1.1 $.getJSON('/', {o:"o=test"}); = GET http://localhost:55332/?o=o%3Dtest HTTP/1.1 And your code generate this get request: GET http://localhost:55332/?{%22id%22:%22C21803C3-1385-462E-ACEA-AFA1E554C635%22} HTTP/1.1 – Simon Edström Feb 06 '12 at 16:15
  • I was more worried about escaping quotations and having to manually build arrays. I know I'm not doing anything out the ordinary here. As an example see [Introducing ASP.NET MVC 3 (Preview 1)](http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx) under the section JavaScript and AJAX Improvements. I even build my data object exactly as he showed, stringified it, but null when hitting the controller. – user1097974 Feb 06 '12 at 16:28
  • Yeah, I read that also, the only diffrent between your code and the example is that you are using get and they are using post. Maybe thats it? I dont know, give it a try – Simon Edström Feb 06 '12 at 16:31
  • See my update above. It does appear to be an issue with POST vs GET, even though JsonRequestBehavior.AllowGet is supposed to allow it. As an aside as well, I created a model and tried binding that way, same exact results. – user1097974 Feb 06 '12 at 16:57

2 Answers2

2

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
}
Simon Edström
  • 6,461
  • 7
  • 32
  • 52
  • I think the lesser of two evils here is to just post. I accept your answer, but I have not tested your binder. Sending a post is just so much simpler. Thank you. I will send this information to Microsoft to see if they know about it, or have a better answer. – user1097974 Feb 06 '12 at 18:31
0

What i think is wrong is, you are trying to stringify o object, while the id you are trying to pass is inside the o object, not in the o object itself.

So try this code

$.getJSON('@Url.Action("GetById", "User")', JSON.stringify(o.id), function () {
    alert('Completed');
});
Quad Coders
  • 668
  • 1
  • 6
  • 21
  • Unfortunately, this is incorrect. It gives me the same error. It also would not work for multiparameter methods. For an example of how JSON.stringify is supposed to work, examine [Using Native JSON](https://developer.mozilla.org/En/Using_native_JSON) – user1097974 Feb 06 '12 at 15:48