tags:

views:

130

answers:

3

For my ASP.Net application I need to use a HTTP REST API that returns a JSON object. Here's how the JSON looks:

message: [
    {
    type: "message"
    href: "/messages/id/23"
    view_href: /this-is-a-test-message/m-p/23
    id: {
        type: "int"
        $: 23
            }
    },
    { //...
    }
]

I could use the DataContractJsonSerializer Class and have custom Classes defined. However, am not sure how keys like "$" would get converted to in .Net.

Any suggestions?

+1  A: 

DataContractJsonSerializer has a lot of limitations and I personally haven't had good experiences working with it.

I would suggest JSON .NET or if you're using .NET 4.0, perhaps an IDynamicObjectMetaProvider.

Example of the latter is here, but there are several other simple implementations out there: http://www.charlierobbins.com/articles/2010/02/11/parsing-json-into-dynamic-objects-using-mgrammar-and-c-4-0/

JeffN825
+2  A: 

This looks like it does something like what you want, with JSON.NET:

using System;
using Newtonsoft.Json.Linq;

class Test
{
    static void Main(string[] args)
    {
        JObject top = new JObject(
            new JProperty("type", "message"),
            new JProperty("href", "/messages/id/23"),
            new JProperty("view_href", "/this-is-a-test-message/m-p/23"),
            new JProperty("id", new JObject(new JProperty("type", "int"),
                                            new JProperty("$", 23))));

        Console.WriteLine(top);

        // Round trip        
        string json = top.ToString();
        JObject reparsed = JObject.Parse(json);
    }
}
Jon Skeet
JSON.Net seems cool.Can you throw some light on how I can use the properties from the reparsed object?Am getting some errors when I do reparsed.Item("response")Note that I populated reparsed object from my JSON string
LVS
@Vidhyashankar: Use the indexer: `reparsed["response"]`
Jon Skeet
+1  A: 

I see no problem to use standard DataContractJsonSerializer to read the data with "$" field. Much more problem I see that you data is not yes in JSON format. If you mean that the data from the question is only an object which will be serialized then the serialized JSON data will be looks like following

{
    "message": [
        {
            "type": "message",
            "href": "\/messages\/id\/23",
            "view_href": "\/this-is-a-test-message\/m-p\/23",
            "id": {
                "type": "int",
                "$": 23
            }
        }
    ]
}

or

var json = '{"message":[{"type":"message","href":"\/messages\/id\/23","view_href":"\/this-is-a-test-message\/m-p\/23","id":{"type":"int","$":23}}]}'

All properties will be double quoted and slash will be escaped (see http://www.json.org/). You can verify on the JSON Validator, that the data are correct JSON data.

To read the data (deserialize) or write (serialize) with respect of DataContractJsonSerializer you can without any problem. Like I mention before you should only use Name properties of DataMember attribute:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization.Json;
using System.Runtime.Serialization;
using System.IO;

namespace DataContractJsonSerializer4 {
    [DataContract]
    public class MyId {
        [DataMember (Order = 0)]
        public string type;
        [DataMember (Order = 1, Name="$")]
        public int value;
    }
    [DataContract]
    public class Message {
        [DataMember (Order = 0)]
        public string type { get; set; }
        [DataMember (Order = 1)]
        public string href { get; set; }
        [DataMember (Order = 2)]
        public string view_href { get; set; }
        [DataMember (Order = 3)]
        public MyId id { get; set; }
    }
    [DataContract]
    public class MessageCollection {
        [DataMember]
        public List<Message> message { get; set; }
    }

    class Program {
        static void Main (string[] args) {
            MessageCollection mc = new MessageCollection () {
                message = new List<Message> () {
                    new Message() {
                        type = "message",
                        href = "/messages/id/23",
                        view_href = "/this-is-a-test-message/m-p/23",
                        id = new MyId() { type="int", value=23}
                    },
                    new Message() {
                        type = "message",
                        href = "/messages/id/24",
                        view_href = "/this-is-a-test-message/m-p/24",
                        id = new MyId() { type="int", value=24}
                    }
                }
            };
            string json =
                "{" +
                    "\"message\": [" +
                        "{" +
                            "\"type\": \"message\"," +
                            "\"href\": \"\\/messages\\/id\\/23\"," +
                            "\"view_href\": \"\\/this-is-a-test-message\\/m-p\\/23\"," +
                            "\"id\": {" +
                                "\"type\": \"int\"," +
                                "\"$\": 23" +
                            "}" +
                        "}," +
                        "{" +
                            "\"type\": \"message\"," +
                            "\"href\": \"\\/messages\\/id\\/24\"," +
                            "\"view_href\": \"\\/this-is-a-test-message\\/m-p\\/24\"," +
                            "\"id\": {" +
                                "\"type\": \"int\"," +
                                "\"$\": 24" +
                            "}" +
                        "}" +
                    "]" +
                "}";

            DataContractJsonSerializer ser = new DataContractJsonSerializer (typeof (MessageCollection));
            using (MemoryStream ms = new MemoryStream (Encoding.Unicode.GetBytes (json))) {
                MessageCollection obj = ser.ReadObject (ms) as MessageCollection;
                Console.WriteLine ("JSON data can be read. The value of the fist $ field is {0}", obj.message[0].id.value);
                using (MemoryStream ms2 = new MemoryStream ()) {
                    ser.WriteObject (ms2, obj);
                    string serializedJson = Encoding.UTF8.GetString (ms2.GetBuffer (), 0, (int)ms2.Length);
                    Console.WriteLine (serializedJson);
                }
            }
            using (MemoryStream memoryStream = new MemoryStream ()) {
                memoryStream.Position = 0;
                ser.WriteObject (memoryStream, mc);

                memoryStream.Flush ();
                memoryStream.Position = 0;
                StreamReader sr = new StreamReader (memoryStream);
                string str = sr.ReadToEnd ();
                Console.WriteLine ("The result of custom serialization:");
                Console.WriteLine (str);
            }
        }
    }
}

The program produce following output

JSON data can be read. The value of the fist $ field is 23
{"message":[{"type":"message","href":"\/messages\/id\/23","view_href":"\/this-is-a-test-message\/m-p\/23","id":{"type":"int","$":23}},{"type":"message","href":"\/messages\/id\/24","view_href":"\/this-is-a-test-message\/m-p\/24","id":{"type":"int","$":24}}]}
The result of custom serialization:
{"message":[{"type":"message","href":"\/messages\/id\/23","view_href":"\/this-is-a-test-message\/m-p\/23","id":{"type":"int","$":23}},{"type":"message","href":"\/messages\/id\/24","view_href":"\/this-is-a-test-message\/m-p\/24","id":{"type":"int","$":24}}]}
Oleg
Am not able to get this working for my JSON where 'message' is repeated multiple times. Otherwise, this is fine.
LVS
@Vidhyashankar: I am sure, that you made a simple error in using multiple 'message' items. Look at the **modified** code and the output of the code in my answer. How you could compare it with the old code you need only modify definition of `MessageCollection mc` and `string json`.
Oleg
@Oleg I see that small error :) Cheers, it works now!
LVS