c# - How to return data in a standard way? -


i trying figure out how return data in standard way. mean when return json or xml nice have 1 format everything(success , errors).

say have following json result.

{   "person": {     "id": 12345,     "firstname": "john",     "lastname": "doe",     "phones": {       "home": "800-123-4567",       "work": "888-555-0000",       "cell": "877-123-1234"     },     "email": [       "jd@example.com",       "jd@example.org"     ],     "dateofbirth": "1980-01-02t00:00:00.000z",     "registered": true,     "emergencycontacts": [       {         "name": "",         "phone": "",         "email": "",         "relationship": "spouse|parent|child|other"       }     ]   } } 

this fine happens if there validation error

i use built in method createerrorresponse

{   "message": "the request invalid.",   "modelstate": {     "item": [       "required property 'name' not found in json. path '', line 1, position 14."     ],     "item.name": [       "the name field required."     ],     "item.price": [       "the field price must between 0 , 999."     ]   } } 

*yes know data not make sense , different data irrelevant structure is.

now happens if have error , in case has custom error code.

i return this(using httperror)

{   "message": "my custom error message",   "customerrorcode": 37 } 

now can see have 3 different formats of json coming back. on client have this

  1. check httpstatuscode
    • if 200 in case parse json using format of person.
    • if 400 validation error or server error.
    • if customer error found use format otherwise use modlestate.

i been working foursquare , seems return same format user have no clue how same sort of thing when it.

  {           "meta": {             "code": 200,              ...errortype , errordetail...           },           "notifications": {              ...notifications...           },           "response": {              ...results...           }         } 

i similar like

would ok request.

{     "meta": {         "code": 200,          "modelstate": {}     },     "response": {         "person": {             "id": 12345,             "firstname": "john",             "lastname": "doe",             "phones": {                 "home": "800-123-4567",                 "work": "888-555-0000",                 "cell": "877-123-1234"             },             "email": [                 "jd@example.com",                 "jd@example.org"             ],             "dateofbirth": "1980-01-02t00:00:00.000z",             "registered": true,             "emergencycontacts": [                 {                     "name": "",                     "phone": "",                     "email": "",                     "relationship": "spouse|parent|child|other"                 }             ]         }     } } 

server error this

{     "meta": {         "code": 500,         "message": "this server error",         "modelstate": {}     },     "response": {} } 

validation this

{     "meta": {         "code": 400,         "message": "validation errors",         "message": "the request invalid.",         "modelstate": {             "item": [                 "required property 'name' not found in json. path '', line 1, position 14."             ],             "item.name": [                 "the name field required."             ],             "item.price": [                 "the field price must between 0 , 999."             ]         }     },     "response": {} } 

but said not sure how , not 100% best way still. @ least should 1 format then?

edit @erik philips

when doing asp.net mvc projects this.

public readonly ivalidation validation;  public personservice(ivalidation validation) {     this.validation = validation; }  public person getperson(int id) {      try     {        return findperson(id);     }     catch(exception ex)     {         //log real error elmah         validation.adderror("internal", "something went wrong");     } }   public class personcontroller {      public readonly ipersonservice personservice;      public personcontroller(ipersonservice personservice)      {        this.personservice = personservice;      }      public actionresult getperson(int id)     {         personservice.getperson(id);          if(personservice.validation.isvalid)         {           //         }         else         {            // else         }          return view();     } } 

i how set keep sort of way. don't think can use interface thinking of this

public personservice() {  }  public responseresult<person> getperson(int id) {     var result = responseresult<person>();     try     {        return findperson(id);     }     catch(exception ex)     {        result.errorcode = 200;        result.msg = "failed";     } }   public class personcontroller {      public readonly ipersonservice personservice;      public personcontroller(ipersonservice personservice)      {        this.personservice = personservice;      }      public httpresponsemessage getperson(int id)     {        var result = personservice.getperson(id);        if(result.isvalid)        {           request.createresponse<responseresult<person>>(httpstatuscode.ok, result);        }           request.createresponse<responseresult<person>>(httpstatuscode.badrequest, result);     } } 

this sort of large question it's design send data has multiple parts, believe easy, small , elegant solution.

this isn't use, example:

first lets build out model represents responses need, or can used when no result data required:

public class responseresult {     public responseresult()     {     }      public responseresult(modelstatedictionary modelstate)     {         this.modelstate = new modelstateresult (modelstate);     }      // request valid, in context of actual request     public bool isvalid { get; set; }     // serialized model state if needed     public modelstateresult modelstate { get; set; } } 

next, there large set of different types of results return, , here generics come in handy:

public class responseresult<t> : responseresult {     public responseresult() : base()     {     }      public responseresult(modelstatedictionary modelstate)         : base(modelstate)     {     }      public responseresult(t data, modelstatedictionary modelstate)         : base (modelstate)     {         this.data = data;     }      public t data { get; set; } } 

so if need return person can return:

var result = responseresult<person>();  result.data = person;  //serialize result , send client. 

my apis can consumed javascript change http status code, , give examples on how use jquery redirect , consume data.

request = $.ajax({   type: "post",   url: url,   data: data,   success: function(data, textstatus, jqxhr)   {     processresponseresult(data);   }   complete: function(e, xhr, settings)   {     if(e.status === 401)     {       // login      }     // else if (e.status == )      else     {       // unknown status code     } )}; 

you may want extend result consumed client may not using http (wcf) in future:

public class responseresult {    ....    ....    public int errorcode { get; set; }    public string errormessage { get; set; } } 

or take step further:

public class responseerrorbase {    public int errorcode { get; set; }    public string errormessage { get; set; } }  public class responseresult {    ....    ....    public responseerrorbase error { get; set; } } 

so add more error types/information in future.

update per comments

comment 1: if have collection of people have..

list<person> persons = new list<person>(); var result = new responseresult<list<person>>(); result.data = persons; 

comment 2: there 2 classes..

if api had call fileexists(filename) don't have return object, call succeeded.

var result = new responseresult(); result.isvalid = fileexists(filename); 

if api wanted return id of new person return new id.

var result = new responseresult<guid?>(); result.isvalid = createperson(personinfo); if (result.isvalid) {   result.data = personinfo.id; } 

or return new successful person object, or null if not successful.

var result = new responseresult<person>(); result.isvalid = createperson(personinfo); if (result.isvalid) {   result.data = person; } 

update per comments

what recommend wrote earlier , include responseerrorbase in responseresult:

public class responseresult {   public responseresult()   {   }    public responseresult(modelstatedictionary modelstate)   {     this.modelstate = new modelstateresult (modelstate);   }    public bool isvalid { get; set; }   public modelstateresult modelstate { get; set; }   public responseerrorbase error { get; set; } } 

then derive error base specific:

// isn't abstract because may want return // non-specific error messages public class responseerrorbase {   public int code { get; set; }   public string message { get; set; } }  public class internalresponseerror : responseerrorbase {   // property specific error   // not errors   public int internalerrorlogid { get; set; } } 

then return (example returning value, you'll want more logic):

var result = new responseresult<person>();  try {   result.data = db.findperson(id); } catch (sqlexception ex) {   var error = responseerrorbase();   error.code = 415;   error.message = "sql exception"; } catch (exception ex) {   var error = internalresponseerror();   error.internalerrorlogid  = log.writeexception(ex);   error.code = 500;   error.message = "internal error"; }  // mvc might like: return this.json(result); 

Comments

Popular posts from this blog

c# - Send Image in Json : 400 Bad request -

jquery - Fancybox - apply a function to several elements -

An easy way to program an Android keyboard layout app -