Server action never invoked - JSON deserialization failure?
I have simple action in my controller:
[HttpPost]
public JsonResult Action(MenuSet menuSet)
{
//...
}
where MenuSet
is:
public class MenuSet
{
private IEnumerable<MenuEntry> _menuEntries;
public IEnumerable<MenuEntry> MenuEntries
{
get { return _menuEntries; }
set { _menuEntries = value; }
}
}
public class MenuEntry
{
private string _parentPageName;
private IEnumerable<string> _orderedPages;
public string ParentPageName
{
get { return _parentPageName; }
set { _parentPageName = value; }
}
public IEnumerable<string> OrderedPages
{
get { return _orderedPages; }
set { _orderedPages = value; }
}
}
From the client side, I'm invoking this action in the way below:
$.post("Controller/Action",
$.param({ MenuEntries: prepareData() }, true),
null,
"json");
where prepareData()
function returns MenuEntries
collection:
function prepareData() {
var menuEntries = new Array();
var menuEntry = {
开发者_StackOverflow社区 ParentPageName: null,
OrderedPages: getPagesOrder()
}
menuEntries.push(menuEntry);
return menuEntries;
}
function getPagesOrder() {
var values = new Array();
values.push('samplePageName')
return values;
}
But the JSON object appears to be not deserialized to the model at the server side - the controller action is never invoked. How to make this work ?
Jarek,
it works fine if you use $ajax, rather than $post. I've added a button to a my index.aspx page as so:
<input type="button" id="btnGo" value="Go" />
also, add a new javascript file and paste the following into it (save it as /scripts/toJson.js):
//Source: http://www.overset.com/2008/04/11/mark-gibsons-json-jquery-updated/
(function($) {
m = {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"': '\\"',
'\\': '\\\\'
},
$.toJSON = function(value, whitelist) {
var a, // The array holding the partial texts.
i, // The loop counter.
k, // The member key.
l, // Length.
r = /["\\\x00-\x1f\x7f-\x9f]/g,
v; // The member value.
switch (typeof value) {
case 'string':
return r.test(value) ?
'"' + value.replace(r, function(a) {
var c = m[a];
if (c) {
return c;
}
c = a.charCodeAt();
return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
}) + '"' :
'"' + value + '"';
case 'number':
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
return String(value);
case 'object':
if (!value) {
return 'null';
}
if (typeof value.toJSON === 'function') {
return $.toJSON(value.toJSON());
}
a = [];
if (typeof value.length === 'number' &&
!(value.propertyIsEnumerable('length'))) {
l = value.length;
for (i = 0; i < l; i += 1) {
a.push($.toJSON(value[i], whitelist) || 'null');
}
return '[' + a.join(',') + ']';
}
if (whitelist) {
l = whitelist.length;
for (i = 0; i < l; i += 1) {
k = whitelist[i];
if (typeof k === 'string') {
v = $.toJSON(value[k], whitelist);
if (v) {
a.push($.toJSON(k) + ':' + v);
}
}
}
} else {
for (k in value) {
if (typeof k === 'string') {
v = $.toJSON(value[k], whitelist);
if (v) {
a.push($.toJSON(k) + ':' + v);
}
}
}
}
return '{' + a.join(',') + '}';
}
};
})(jQuery);
reference this new file in your index.aspx
<script src= "/scripts/toJson.js" type="text/javascript"></script>
and replaced the $post javascript with:
$(document).ready(function() {
$('#btnGo').click(function() {
$.ajax({
type: "POST",
url: '<%=Url.Content("~/Home/Action") %>',
dataType: "json",
data: { MenuEntries: prepareData() },
success: function(msg) {
alert(msg);
},
error: function(xhr) { alert(xhr.statusText); }
});
});
});
function prepareData() {
var menuEntries = new Array();
var menuEntry = {
ParentPageName: "myPageName",
OrderedPages: getPagesOrder()
}
menuEntries.push(menuEntry);
// this serialises the javascript array correctly
return $.toJSON(menuEntries);
}
try changing the action to the code below and try playing about with that (this gives you two options to examine the posted data):
[HttpPost]
public JsonResult Action(FormCollection formCollection)
{
NameValueCollection test = HttpContext.Request.Form;
// return Json(test[0]);
return Json(formCollection[0]);
}
it correctly deserialises inside the 'Action' action in the controller.
give it a try. i'm sure it's 'fixed'
[edit] - halfaway fixed... you'll need to work on how you play with the object. i.e. either via the formCollection or via the test varibale. both give the object in different guises.!!
First
You could as well use IList<MenuEntry>
as parameter type in your action method.
Second
These two blog posts will help you get things done with automatic model validation which is not the case with the other guy's solution.
Asp.net MVC model binding to List<T>
Sending complex JSON objects to Asp.net MVC using jQuery
You can use Phil Haack's
solution for passing json to action method of controller.
Hope this helps!
精彩评论