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

Popular posts from this blog

jquery - How can I dynamically add a browser tab? -

node.js - Getting the socket id,user id pair of a logged in user(s) -

keyboard - C++ GetAsyncKeyState alternative -