0

I have a C# class that receives a JSON string, and deserialises it into a dynamic.

json = @"{  
    "Id": "97dc4a96-43cf-48bd-9358-8f33e910594e",  
    "RepId": 90037,  
    "Something": true, 
    "SomethingElse": "abcdefg",
    "Thing_1_of_MaybeDozens": 55
}";

dynamic jsonData = JsonConvert.DeserializeObject(json);

I can't deserialse into a class because while each JSON string will always have two known data elements (Id, and RepId), the rest of the string may have many elements that I do not know ahead of time their names, or how many of them there are.

I can always ask for jsonData.Id, or jsonData.RepId, but I do not know how many other elements there may be, nor how to refer to them.

I need something similar to JavaScript's Object.Keys(myObject).

Anyone knows how to do similar in C# with a Newtonsoft Deserialised JSON string?

Ken White
  • 123,280
  • 14
  • 225
  • 444
KWallace
  • 1,570
  • 1
  • 15
  • 25
  • Does this answer your question? [Deserialize JSON into C# dynamic object?](https://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object) – Mark Schultheiss Jan 16 '22 at 01:54
  • 1
    Did you try to cast to `ExpandObject`? If you can, you can enumerate keys like a regular dictionay. – GibbOne Jan 16 '22 at 02:04
  • 1
    Does this answer your question? [How to serialize a Dictionary as part of its parent object using Json.Net](https://stackoverflow.com/questions/14893614/how-to-serialize-a-dictionary-as-part-of-its-parent-object-using-json-net) – Charlieface Jan 16 '22 at 03:11
  • 1
    You're looking for `[JsonExtensionData]` on a `Dictionary` property – Charlieface Jan 16 '22 at 03:12
  • Hi Mark, and thanks for the suggestion. Yes, that would have helped. While entering my post's title, if SO had suggested that one I probably would have taken it. Good to know, now, though. SO doesn't always recommend similar questions that actually match. So, thanks! – KWallace Jan 16 '22 at 19:30

2 Answers2

3

You can use Reflection:

public Dictionary<string, object> DynamicToDictionary(dynamic obj)
{
     var dict = new Dictionary<string, object>();
     foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(obj))
     {
        object obj2 = pd.GetValue(obj);
        dict.Add(pd.Name, obj2);
     }
     return dict;
}

Now you may use the dictionary's TryGetValue(), and ContainsKey().

KWallace
  • 1,570
  • 1
  • 15
  • 25
Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
  • 2
    Perfect! That's exactly what I was looking for! – KWallace Jan 16 '22 at 19:39
  • 1
    @KirbyL.Wallace glad if I could help – Ashkan Mobayen Khiabani Jan 16 '22 at 20:09
  • This is working just great, except when one of the properties is an empty array (sorry, I can't format it properly in a comment: { "Id": "97dc4a96-43cf-48bd-9358-8f33e910594e", "RepId": 90037, "Weight": 215, "ScaleReadings": [], "Email": "pacer@yahoo.com" } ScaleReadings throws error when the property is an empty array: 'The name 'Value' is bound to a method and cannot be used like a property.' @Ashkan Mobayen Khiabani – KWallace Jan 16 '22 at 21:28
  • @KirbyL.Wallace there are many possible solutions to this, but the easiest ones I think would be 1. `if(pd.IsArray()) { //do something }` or 2. just remove the empty arrays from json string : `[\w"]+\s*:\s*\[\]\s*,*` , here is the example [https://regex101.com/r/1sNJ1T/1](https://regex101.com/r/1sNJ1T/1) – Ashkan Mobayen Khiabani Jan 16 '22 at 22:08
  • 1
    pd.IsArray() will be great. Thanks. – KWallace Jan 17 '22 at 07:28
0

try to use Newtonsoft.Json extensions

var data = JsonConvert.DeserializeObject<Data>(json);

list of keys

List<string> additionalKeys=data.AdditionalData.Select(ad => ad.Key).ToList();

output

["Something","SomethingElse","Thing_1_of_MaybeDozens"]

how to use

var id = data.Id;  //97dc4a96-43cf-48bd-9358-8f33e910594e

var somethingElse = data.AdditionalData["SomethingElse"]; // abcdefg

class

public class Data
{
    // normal deserialization
    public string Id { get; set; }
    public long RepId { get; set; }

    //additional data
    [JsonExtensionData]
    public Dictionary<string, object> AdditionalData {get;set;}
}
Serge
  • 40,935
  • 4
  • 18
  • 45