c# - Dynamically creating JSON objects from reflected methods -
first off, i'm sorry if i'm off on terminology - bare me.
i've since getting bunch of so hivemind been able create rest api (c#, mvc) handles dynamic (at least that's want call it) calls through catching string param , finding correct method through using reflection.
var mytype = typeof(jaberodc.jaberodc.jaberodc); var method = mytype .getmethods(bindingflags.public | bindingflags.instance | bindingflags.declaredonly) .single(mi =>mi.returntype == typeof(dataset) && string.equals(mi.name, param, stringcomparison.ordinalignorecase)); var subject = activator.createinstance(mytype); var result = method.invoke(subject, new object[] { "", constr, "", 0, 0, null }); dataset ds = (dataset)result;
what need sort of advice on how handle various results dynamically. meaning need understanding how either create class handles 0=>n columns rows in datatable (after getting dt ds), or how serialize data without creating instances of above mentioned class.
again, i'm sorry if terminology off here.
i've been thrown deep-end @ current employer create rest api datacomponent has few hundred methods. api works when using below code:
list<worksite> arr2 = new list<worksite>(); foreach (datatable table in ds.tables) { foreach (datarow row in table.rows) { string id = row["jobid"].tostring(); string name = row["jobname"].tostring(); string site = row["sitename"].tostring(); arr2.add(new worksite { id = id, jobname = name, sitename = site }); } }
basically handles worksites (a specific dataset in datacomponent).
my current solution:
public string getfromparam(string param) { var mytype = typeof(jaberodc.jaberodc.jaberodc); var method = mytype .getmethods(bindingflags.public | bindingflags.instance | bindingflags.declaredonly) .single(mi =>mi.returntype == typeof(dataset) && string.equals(mi.name, param, stringcomparison.ordinalignorecase)); var subject = activator.createinstance(mytype); var result = method.invoke(subject, new object[] { "", constr, "", 0, 0, null }); dataset ds = (dataset)result; list<generatemodel> arr2 = new list<generatemodel>(); int count = 0; list<dictionary<string, object>> rows = new list<dictionary<string, object>>(); dictionary <string, object> dicrow; foreach (datatable table in ds.tables) { foreach (datarow row in table.rows) { dicrow = new dictionary<string, object>(); foreach (datacolumn col in table.columns){ dicrow.add(col.columnname, row[col]); } rows.add(dicrow); } } // (int = 0; < ds.tables.) string json = jsonconvert.serializeobject(rows); return json; }
i'm using proposed solution in marked answer whilst using dynamic solution issue datakey-value pairs using dictionary hold them.
i agree clint's comment using json.net newtonsoft. has lot of helper methods make life easier.
ideally, creating 1 controller per type of data expect receive. can use incoming data create instance of class modeled after receiving. restful apis , mvc, treat incoming data formdatacollection, incoming stream of keyvalue pairs must process sequentially. here code sample point in right direction:
// post api/mycontrollername public httpresponsemessage post(formdatacollection fdc) { try { if (fdc != null) { myclass myinstance = new myclass(); ienumerator<keyvaluepair<string, string>> pairs = fdc.getenumerator(); while (pairs.movenext()) { switch (pairs.current.key) { case "phonenumber": myinstance.phonenumber = pairs.current.value; break; ... default: // handle additional columns break; } } // stuff myinstance // respond ok notification } else { // respond bad request notification } } catch (exception ex) { // respond internal server error notification } }
if must handle multiple data types same controller, there may particular data field give clue receiving can handle appropriately. if genuinely have no idea receiving @ time, may able cast dynamic type , use reflection, sounds data sender setting tough integration in case - not how engineer api...
edit: (to clarify based on comments) appears want accept requests number of data types using single controller, , return datatable results, though don't know in advance fields datatable contain.
first, unless specific requirement, wouldn't use datatable because not platform-independent solution - if requesting application in non-.net language, have easier time parsing json array compared datatable. if must use datatable, can .net's datatable.toxml() extension method, have run issues special characters not converting xml , other gotchas approach.
if want go recommended json route, data request have sufficient query database (ie: requesttype = "jobsitereport", mindate = "7/1/2016", maxdate = "7/12/2016"). use query database or generate data (into dataset or datatable if comfortable with) depending on "requesttype" is. use linq or loop or other method transform datatable object array (this anonymous type if want, prefer keeping things typed when have option.) pseudocode, should give idea of mean:
//using newtonsoft.json; list<myobject> objects = new list<myobject>(); (int = 0; < dt.rows.count; i++) { myobject obj = new myobject() obj.time = dt.rows[i]["time"]; obj.person = dt.rows[i]["personid"]; ... objects.add(obj); } string json = jsonconvert.serializeobject(objects.toarray());
now have string contains json data of results datatable. can return that. (you use sqldatareader accomplish same result without using datatable intermediate step - populate list sqldatareader, convert list array, serialize array json.)
if inventing schema, should create documentation requester should expect receive.
json.net has methods deserializing typed objects json, deserializing anonymous types, etc. should read on available - i'm sure has perfect trying achieve.
Comments
Post a Comment