views:

81

answers:

2

I see a lot of simple examples of JSON DeSerialization, but when it comes to anything slightly more complex, there is a lacking of samples.

I'm looking at deserializing Responses from GetResponse's API:

Simple e.g.

{
    "result" : {
        "updated" : "1"
    },
    "error" : null
}

Another:

{
    "result" : null,
    "error"  : "Missing campaign"
}

Here's another more complex potential response:

{
    "result" : {
        "CAMPAIGN_ID" : { // <-- This value will be different for each Campaign
            "name"              : "my_campaign_1",
            "from_name"         : "My From Name",
            "from_email"        : "[email protected]",
            "reply_to_email"    : "[email protected]",
            "created_on"        : "2010-01-01 00:00:00"
        }
    },
    "error" : null
}

For that last one, what should my object look like?

I initially toyed with just doing something like this...

 private struct GenericResult {
     public string error;
     public Dictionary<string, object> result;
 }

This will work for all my reponses, but then to access the object's properties I'll have to cast it, if I'm not mistaken.

I want to use it like this:

JavaScriptSerializer jss = new JavaScriptSerializer();
var r = jss.Deserialize<GenericResult>(response_string);

// or... if I'm going to use a non-Generic object
var r = jss.Deserialize<GetCampaignResult>(response_string);

EDIT

After getting the data back, the actual structure has one hitch. Here's an actual sample:

The value

{
    "error":null,
    "result":
        {"ABQz": { // <-- As you can see, this is NOT a class name.
           "from_email" : "[email protected]",
           "created_on" : "2010-10-15 12:40:00",
           "name"       : "test_new_subscribers",
           "from_name"  : "John Smith",
           "reply_to_email": "[email protected]"
        }
    }
}

Now that I don't know what that value is going to be, I'm stumped. I'd like to include that value as an ID for the Campaign object.

+1  A: 

I see three objects from your example.

Class CampaignId {

    String name ;
    String from_Name ;
    String from_Email ;
    \\ etc
}

Class Result {
   CampaignId campaignId  ;
}


Class RpcResponse {
   String error ;
   Result result ;
}

Do you need DataMember attributes?

a good article in F# that I used when learning JSON serialization: http://blogs.msdn.com/b/jomo_fisher/archive/2010/03/06/neat-sample-f-and-freebase.aspx

Developing on the response below, you may want to introduce some generics:

Class CampaignId {

    String name ;
    String from_Name ;
    String from_Email ;
    \\ etc
}

Class Result<T> {
   <T> data ;
}


Class RpcResponse<T> {
   String error ;
   Result<T> result ;
}

And intialize the serializer with

JavaScriptSerializer jss = new JavaScriptSerializer(); 
var r = jss.Deserialize<RpcResponse<CampaignId>>(response_string); 

another decent tutorial:

http://publicityson.blogspot.com/2010/06/datacontractjsonserializer-versus.html

akaphenom
Actually DCS doesn't require those after 3.5
drachenstern
good to know. I am having my team build Silverlight / F# UI to a Jboss Server w. JSON Rpc. But we use the JSON serialization very nicely and do a lot with generics. A lot of the Json RPC libraries have some kind of envelope - the result in this example - witch references a payload...
akaphenom
I think I'd need DataContract attributes if I was using the DataContractJSonSerializer. I'm just not sure whether I should use that or the JavascriptSerializer (un-deprecated as of 3.5 SP1)
Atømix
Thanks drachentern... didn't know that.
Atømix
I don't know the details on the differences between them, we rely on DataContractJSonSerializer but we are using f# and the engineers are writing the code (i pretend to manage these days and come here for my coding fix)
akaphenom
@akaphenom ~ I used to try and decorate mine too, and it's advised, but not required. Also note: I don't use the DCS JSON deserializer on my items. Of course I'm using a `[WebMethod]` decorated element so that might be why. I forget now.
drachenstern
After getting the data back, I've updated the JSon returned (See original question). The `CAMPAIGN_ID` is an ID. Since I don't want classes for each campaign, I need to do some custom serialization.
Atømix
+1  A: 
{
    "result" : {
        "CAMPAIGN_ID" : {
            "name"              : "my_campaign_1",
            "from_name"         : "My From Name",
            "from_email"        : "[email protected]",
            "reply_to_email"    : "[email protected]",
            "created_on"        : "2010-01-01 00:00:00"
        }
    },
    "error" : null
}

I would have one that looked like this: [attempting without a safetynet .. where's my compiler!?!? ;) ]

public class TheResponse {
  public RESULT result { get; set; }
  public object error { get; set; }
}

public class RESULT {
  public CAMPAIGN_ID campaign_ID { get; set; }
}

public class CAMPAIGN_ID {
  public string name { get; set; }
  public string from_name { get; set; }
  public string from_email { get; set; }
  public string reply_to_email { get; set; }
  public string created_on { get; set; }
}

But yes, you'll have to cast it somewhere, somehow, sometime.

But I think that code right there translates between the two.


I'm not using nested objects like you have, but I'm doing something similar (I have a List so that works sorta)

http://pastebin.com/7Tzr2RBz -> http://pastebin.com/NQwu3hZK (updated)

http://pastebin.com/a0aMzcE4

Those two work together (one from the client (JS), one from the server (C#)) so you can see how I'm doing mine (not that it's likely to help, but I try)

Happy JSONing

drachenstern
Won't the JavascriptDeserialize<TheResponse> take care of the casting? That's how I understand it, anyhow.
Atømix
It should, yes. Unless you use objects (like I did for error, where I don't know "for sure" what it will be)
drachenstern
@Atømix ~ I don't even use a json deserializer. See my pastebins
drachenstern
haha, I just realized (while re-reading the code I posted) that I am duplicating effort in two places ... /facepalm indeed. Yay for young code!!! `foreach ( WidgetPageItems w in Items ) { w.ColumnOrder = counter; counter++; }` AND `$(items).each(function() { count++; $(this).attr('columnorder', count); str.push(...); });` but at least it shows how to work with JSON elements before and after ;) [and my crappy coding style!]
drachenstern