0

I bring my Json data in using the downloadstring() function. I then deserialize it (will show below) but I am not sure what happens to the data after that. I don't know how to call it or how to manipulate it, let alone find it. I'm new to Json, this is obviously a really easy question, but I can't figure it out.

Here is the code

var data = c.DownloadString("http:...");
dynamic jsdonData = JsonConvert.DeserializeObject<dynamic>(data);
Console.WriteLine(jsonData);?????????????????

The Json Data looks similar to this.

"$id":"1",
  "$values":[  
    {  
      "$id":"2",
      "ID":....,
      "MSSCompanyID":....,
      "CircuitID":"....",
      "CompanyName":"...",
      "Metrics":{  
        "$id":"3",
        "$values":[  
          {  
            "$id":"4",
            "longId":1164568,
            "unit":"......",
            "name":"...."
          },
          {  
            "$id":"5",
            "longId":1164757,
            "unit":".....",
            "name":"......"
          }
        ]
      }
    },
    {  
      "$id":"6",
      "ID":....,
      "MSSCompanyID":......,
      "CircuitID":"......",
      "CompanyName":"....",
      "Metrics":{  
        "$id":"7",
        "$values":[  
          {  
            "$id":"8",
            "longId":...,
            "unit":".......",
            "name":"......."
          },
          {  
            "$id":"9",
            "longId":1164757,
            "unit":"......",
            "name":".........."
          }
        ]
      }
    },    

The Json is valid, the downloadstring DOES pull the json like it should. I am not sure about the deserializing though.

Stanfrancisco
  • 352
  • 1
  • 7
  • 24
  • 1
    Ask yourself this: Do you always now what data will be inside or not? If yes, create a POCO model and `DeserializeObject`. If no, use `JObject.Parse` and dynamically inspect json. – zaitsman May 29 '15 at 13:57
  • 3
    C# properties can't start with a dollar sign. – krillgar May 29 '15 at 13:58
  • 1
    Why don't you breakpoint the `Console.WriteLine(...` part and then explore the generated object in the debugger, to see what the .NET runtime generated? That will answer your question. – Der Kommissar May 29 '15 at 13:58
  • 1
    This should help you get started: http://stackoverflow.com/questions/11126242/using-jsonconvert-deserializeobject-to-deserialize-json-to-a-c-sharp-poco-class – Cory May 29 '15 at 13:59
  • 3
    @krillgar $id is syntax put into place by Newtonsoft (and probably a few other serializers/deserlizers as well) to specify order to avoid circular reference issues. It's disabled with var json = config.Formatters.JsonFormatter; json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None; As a result, if you are using a decent enough serializer, it'll ignore the syntax when deserializing your JSON. – David L May 29 '15 at 13:59
  • 1
    You can always interegate a dymanic object : `myDynamic.hello`. If it doesn't exist i'm sure it throws an error. But the common way is to deserialise into a c# object graph – Callum Linington May 29 '15 at 14:15
  • @EBrown I did what you asked. The data is deserialized and everything is there but it removes the "$id":"1", "$values": from the beginning. I still am not sure how to actually use this data, or call it,or just print it. – Stanfrancisco May 29 '15 at 14:55
  • 1
    What do you mean it `removes the "$id":"1", "$values": from the beginning`? That is a **very unclear** statement. – Der Kommissar May 29 '15 at 14:58
  • @CallumLinington The data exists. And I'm able to call it fine now; thanks for your help. You should post an answer saying how to call it, and I'll mark as the answer – Stanfrancisco May 29 '15 at 14:58
  • @Ebrown I don't think it's that unclear. If you read the code above the very first things listed on the json are $id and $values. Those are removed after I deserialize them. I assume it's because of the $. I am able to call the information I needed now though. I just didn't know how to call it. Working now – Stanfrancisco May 29 '15 at 15:00
  • 1
    Without knowing **where** they are supposed to be that they `were removed` from, it's **extremely unclear.** Was the dollar sign (`$`) removed, were the entire nodes removed, were the keys removed? What **exactly** happened to the object. If it works however, then that is the important part. – Der Kommissar May 29 '15 at 15:03
  • @EBrown The word "$id" and the word "$values" were removed from the beginning of the json data. the "$id" inside every individual data set were also removed. It's not a big deal, it works either way. I don't know exactly what happened to them, I'm sure they are just ignored by the deserializer. Thanks for your help! – Stanfrancisco May 29 '15 at 15:07
  • 1
    @AustinDonley Ah, in that case you could potentially fix that with a little pre-parsing: simply build a `Regex` (or string-replacement system) that will replace instances of `"$IDENTIFIER":` with `"IDENTIFIER":`. This should maintain the original data. – Der Kommissar May 29 '15 at 15:08
  • @EBrown Thank you. I don't really NEED that data, though. But I didn't know that feature existed. Adding to my notebook. I'll experiment with that a little later. – Stanfrancisco May 29 '15 at 15:17
  • 1
    @AustinDonley A basic `data = data.Replace("\"$", "\"");` would replace any instance of a dollar-sign beginning in **any** string. (I.e. `"$id"` would become `"id"`) It also, unfortunately, has the side effect that any dollar-values in a string (I.e. `"$125.52"`) will be replaced as well. (Would become: `"125.52"`.) A regex could easily take care of this, with something like `\"$[a-zA-Z0-9]*?\":`, which would assist in the guarantee that your **values** would not be replaced. – Der Kommissar May 29 '15 at 15:23

2 Answers2

1

Another answer is to use NuGet to grab JSON.NET.

Create a POCO class that could represent a JSON object:

public class CompanyDetails
{
    public int ID { get; set; }

    public int MSSCompanyID { get; set; }

    public int CircuitID { get; set; }

    public string CompanyName { get; set; }

    public Metric[] Metrics { get; set; }
}

public class Metric
{
    public int LongId { get; set; }

    public string Unit { get; set; }

    public string Name { get; set; }
}

HINT: If you don't care about a certain object not being deserialised, you can make the type of that property ExpandoObject, which means C# will take care of "creating" the necessary dynamic class structures. ExpandoObject is basically dynamic.

Using JsonConvert from the JSON.NET library you can deserialise it like this:

public CompanyDetails[] GetDetails(string json)
{
    // this adds automatic camel casing conversions
    JsonConvert.DefaultSettings = () => new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };

    return JsonConvert.DeserializeObject<CompanyDetails[]>(json);
}

So now, you will have your JSON deserialised into a lovely C# object graph. You can now traverse this till your hearts content. Even chuck in the composite or visitor pattern if you want.

REMEMBER: I use CompanyDetails[] this could also be ICollection<>, Collection<>, IEnumerable<> or List<> etc. etc.

Callum Linington
  • 14,213
  • 12
  • 75
  • 154
0

Personally the following is how I have deserialized a Json string similar to yours above:

public static T DeSerializeJSon<T>(string JSON)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            DataContractJsonSerializer ds = new DataContractJsonSerializer(typeof(T));
            var bytes = Encoding.UTF8.GetBytes(JSON);
            stream.Write(bytes, 0, bytes.Length);                
            stream.Position = 0;
            T jsonobject = (T)ds.ReadObject(stream);
            return jsonobject;
        }
    }

As you can see it is easier to manipulate this string once deserialized because it will be contained within an object.

For your reference here is how I would then serialize:

       public static string SerializeJSon<T>(T objectData)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            DataContractJsonSerializer ds = new DataContractJsonSerializer(typeof(T));
            ds.WriteObject(stream, objectData);
            return Encoding.UTF8.GetString(stream.ToArray());
        }
    }

These are both static methods as they are contained within a class library I have created to save code duplication.

Hopefully this sheds a little more light :)

  • Thanks for the info. Will try some things and see where I get. – Stanfrancisco May 29 '15 at 14:12
  • Honestly this makes no sense to me. Why are you using stream? Why aren't you using a get;set; like every other json question in the site? Your method is way different than anything I can find. – Stanfrancisco May 29 '15 at 14:52
  • 1
    @AustinDonley The `DataContractJsonSerializer` is another alternative for **JSON Serialization/Deserialization** that can be used instead of `Json.Net`, or `System.Web.Script.Serialization.JavaScriptSerializer` (or whatever other JSON Serializer is out there). You use it in a different manner than those. – Der Kommissar May 29 '15 at 15:05
  • Oh okay okay. Neat. Good to know. – Stanfrancisco May 29 '15 at 15:08
  • 1
    The use of the streamreader lends itself to the aim of casting the result of the ReadObject (expects a stream to be passed to it) to a generic type defined as T which will therefore be returned. As a previous (now deleted) comment mentioned, if you knew the JSON format, I would create a schema for it, generate the class, then use this as the object to deserialize against. – CraigyJ88 May 29 '15 at 15:11