c# - JSON.Net in Api controllers w/ param containing Dictionary is always null -
i've seen tutorials out there claim work, outdated or not work.
how can use json.net serialize , deserialize data received , sent api controllers?
we using vs2012.
update
i have model this
public class searchmodel { public int pageindex { get; set; } public int pagesize { get; set; } public dictionary<string, object> terms { get; set; } }
and api controller this
public class modelsearchapicontroller : apicontroller { public list<model> get([fromuri] searchmodel search) { return new list<model>(); } }
however, search
provides correct value set in ajax request, property terms
empty dictionary.
i know can provide value [ { key:"foo", value:123 } ]
why can't pass normal json object (ie { foo:123 }
) ??? why can serialize dictionary
nice standard json object, cannot take exact same object , recreate dictionary
. beyound me.
edit
in other words, if browser sends these arguments :
pageindex: 0 pagesize: 100 terms[foo]: bar terms[buz]: 1234
what required object signature? because object mentionned above not work , dictionary empty.
json.net is default serializer asp.net web api - can convert between json , clr objects, , json input. however, you're not trying convert json input searchmodel - you're trying convert uri-based format similar application/x-www-form-urlencoded, clr type searchmodel, , not supported json.net (it's not json!). in general, serializers used convert (on incoming requests) request body action parameter.
let's @ (complete) example below (assuming default route, "api/{controller}"
). it's similar question, added post method in addition method.
public class modelsearchapicontroller : apicontroller { public list<model> get([fromuri] searchmodel search) { return new list<model> { new model { pageindex = search.pageindex, pagesize = search.pagesize, terms = search.terms } }; } public list<model> post(searchmodel search) { return new list<model> { new model { pageindex = search.pageindex, pagesize = search.pagesize, terms = search.terms } }; } } public class model { public int pageindex { get; set; } public int pagesize { get; set; } public dictionary<string, object> terms { get; set; } } public class searchmodel { public int pageindex { get; set; } public int pagesize { get; set; } public dictionary<string, object> terms { get; set; } }
if send request server:
post http://localhost:64699/api/modelsearchapi http/1.1 user-agent: fiddler host: localhost:64699 content-type: application/json content-length: 65 {"pageindex":1,"pagesize":10,"terms":{"foo":"bar","foo2":"bar2"}}
it bound, expect, searchmodel parameter - terms
property dictionary 2 entries (foo=bar, foo2=bar2).
now, parameter. asp.net web api has concept of model binders , value provider, component convert between query string action parameters. default binder / provider not support "arbitrary" name/value pair syntax *for dictionary inside complex types. can, pointed out, use key/value pair syntax, , understood, shown below.
get http://localhost:64699/api/modelsearchapi?pageindex=1&pagesize=10&terms[0][key]=foo&terms[0][value]=bar http/1.1 user-agent: fiddler host: localhost:64699
now, problem have 2 options. can change api use custom model binder or value provider knows how understand "simple" name/value syntax, shown below:
public class modelsearchapicontroller : apicontroller { public list<model> get([modelbinder(typeof(mysearchmodelbinder))] searchmodel search) { return new list<model> { new model { pageindex = search.pageindex, pagesize = search.pagesize, terms = search.terms } }; } } public class mysearchmodelbinder : imodelbinder { public bool bindmodel(httpactioncontext actioncontext, modelbindingcontext bindingcontext) { searchmodel value = new searchmodel(); value.terms = new dictionary<string,object>(); foreach (var queryparams in actioncontext.request.getquerynamevaluepairs()) { if (queryparams.key == "pageindex") { value.pageindex = int.parse(queryparams.value); } else if (queryparams.key == "pagesize") { value.pagesize = int.parse(queryparams.value); } else if (queryparams.key.startswith("terms.")) { value.terms.add(queryparams.key.substring("terms.".length), queryparams.value); } } bindingcontext.model = value; return true; } }
another option pre-process input data on client prior sending server, using function similar 1 below.
function objtokvparray(obj) { var result = []; var k; (k in obj) { if (obj.hasownproperty(k)) { result.push({ key: k, value: obj[k] }); } } return result; }
Comments
Post a Comment