Home > Software design >  C# Parsing Json string returned from GraphQL
C# Parsing Json string returned from GraphQL

Time:02-24

I'm running into issues parsing a json reponse from GraphQL. The issue is the array will come back with more arrays half the time. My code is just getting out of hand and ugly.

Json file (trimmed it a bit. It can be 20 data arrays)

{
  "activity_logs": [
    {
      "data": "{\"board_id\":2165785546,\"group_id\":\"new_group2051\",\"is_top_group\":false,\"pulse_id\":2165787062,\"pulse_name\":\"Tyler\",\"column_id\":\"email_address\",\"column_type\":\"email\",\"column_title\":\"Email Address\",\"value\":{\"column_settings\":{\"includePulseInSubject\":true,\"ccPulse\":true,\"bccList\":\"\"}},\"previous_value\":{\"email\":\"[email protected]\",\"text\":\"[email protected]\",\"changed_at\":\"2022-02-15T21:18:48.297Z\",\"column_settings\":{\"includePulseInSubject\":true,\"ccPulse\":true,\"bccList\":\"\"}},\"is_column_with_hide_permissions\":false,\"previous_textual_value\":\"[email protected]\"}"
    },
    {
      "data": "{\"board_id\":2165785546,\"group_id\":\"new_group2051\",\"is_top_group\":false,\"pulse_id\":216578711,\"pulse_name\":\"Nicholas \",\"column_id\":\"email_address\",\"column_type\":\"email\",\"column_title\":\"Email Address\",\"value\":{\"column_settings\":{\"includePulseInSubject\":true,\"ccPulse\":true,\"bccList\":\"\"}},\"previous_value\":{\"email\":\"[email protected]\",\"text\":\"[email protected]\",\"changed_at\":\"2022-02-16T04:44:52.046Z\",\"column_settings\":{\"includePulseInSubject\":true,\"ccPulse\":true,\"bccList\":\"\"}},\"is_column_with_hide_permissions\":false,\"previous_textual_value\":\"[email protected]\"}"
    },
    {
      "data": "{\"board_id\":2165785546,\"group_id\":\"new_group2051\",\"is_top_group\":false,\"pulse_id\":216578711,\"pulse_name\":\"Nicholas \",\"column_id\":\"batch_5\",\"column_type\":\"text\",\"column_title\":\"Batch #\",\"value\":{\"value\":\"75\"},\"previous_value\":{\"value\":\"74\"},\"is_column_with_hide_permissions\":false}"
    },
    {
      "data": "{\"board_id\":2165785546,\"group_id\":\"new_group2051\",\"pulse_id\":216578711,\"is_top_group\":false,\"value\":{\"name\":\"Nicholas \"},\"previous_value\":{\"name\":\"Nicholas \"},\"column_type\":\"name\",\"column_title\":\"Name\"}"
    }
  ]
}

Random "get it to work" attempt after giving up on making is a List based on a Class. The IContainers within IContainers were getting very complex.

var responseData = JObject.Parse(responseText).SelectToken("data").SelectToken("boards").SelectToken("activity_logs");
dynamic updatedRecords = JsonConvert.DeserializeObject(responseData.ToString());

foreach (var record in updatedRecords)
{
List<Dictionary<string, string>> records = new List<Dictionary<string, string>>();
Dictionary<string, string> fields = new Dictionary<string, string>();
dynamic updates = JsonConvert.DeserializeObject(JObject.Parse(record.ToString()).SelectToken("data").ToString());
foreach(var update in updates)
{
    switch (update.Name.ToString())
    {
        case "column_id":
            fields.Add(update.Name.ToString(), update.Value.ToString());
            break;
        case "pulse_name":
            fields.Add(update.Name.ToString(), update.Value.ToString());
            break;
        case "value":
            dynamic values = JsonConvert.DeserializeObject(JObject.Parse(update.Value.ToString()));
            if (update.Name.ToString().Contains("column_settings"))
            {
                foreach (var value in values)
                {
                    dynamic columns = JsonConvert.DeserializeObject(JObject.Parse(value.Value.ToString()));
                    foreach(var column in columns)
                    {
                        fields.Add($"Value_{column.Name.ToString()}", column.Value.ToString());
                    }
                                                
                }
            }
            else
            {
                foreach (var value in values)
                {
                    fields.Add($"Value_{value.Name.ToString()}", value.Value.ToString());
                }
            }
                                        
            break;
        case "previous_value":
            dynamic prevValues = JsonConvert.DeserializeObject(JObject.Parse(update.Value.ToString()));
            foreach (var prevalue in prevValues)
            {
                fields.Add($"Prevalue_{prevalue.Name.ToString()}", prevalue.Value.ToString());
            }
            break;
        case "previous_textual_value":
            fields.Add(update.Name.ToString(), update.Value.ToString());
            break;
    }
}
if (fields.Count > 0)
{
    records.Add(fields);
    fields.Clear();
}
}

My Error when I get to:

dynamic values = JsonConvert.DeserializeObject(JObject.Parse(update.Value.ToString()));
-       $exception  {"The best overloaded method match for 'Newtonsoft.Json.JsonConvert.DeserializeObject(string)' has some invalid arguments"} Microsoft.CSharp.RuntimeBinder.RuntimeBinderException

CodePudding user response:

This might not solve all your issues, but for the specific exception you are running into, it is because you are trying to deserialize a JObject instead of string.

Probably you just want:

dynamic values = JsonConvert.DeserializeObject(update.Value.ToString());

CodePudding user response:

You have to pass in a string to DeserializeObject instead of a JSON object.

Another way would be get your JSON mapped to a POCO types as follows, easy way to do is on Visual Studio (Copy your JSON contents, on Visual Studio create a new empty class -> Edit-> Past Special -> Paste JSON as classes)

public class LogsRoot
{
    public Activity_Logs[] activity_logs { get; set; }
}

public class Activity_Logs
{
    public string data { get; set; }
}

public class DataRoot
{
    public long board_id { get; set; }
    public string group_id { get; set; }
    public bool is_top_group { get; set; }
    public long pulse_id { get; set; }
    public string pulse_name { get; set; }
    public string column_id { get; set; }
    public string column_type { get; set; }
    public string column_title { get; set; }
    public Value value { get; set; }
    public Previous_Value previous_value { get; set; }
    public bool is_column_with_hide_permissions { get; set; }
    public string previous_textual_value { get; set; }
}

public class Value
{
    public Column_Settings column_settings { get; set; }
}

public class Column_Settings
{
    public bool includePulseInSubject { get; set; }
    public bool ccPulse { get; set; }
    public string bccList { get; set; }
}

public class Previous_Value
{
    public string email { get; set; }
    public string text { get; set; }
    public DateTime changed_at { get; set; }
    public Column_Settings1 column_settings { get; set; }
}

public class Column_Settings1
{
    public bool includePulseInSubject { get; set; }
    public bool ccPulse { get; set; }
    public string bccList { get; set; }
}

Then load the JSON and manipulate as follows,

var json = File.ReadAllText("data.json");
var rootLogs = JsonConvert.DeserializeObject<LogsRoot>(json);

Dictionary<string, string> fields = new Dictionary<string, string>();

foreach (var logJson in rootLogs.activity_logs)
{
    var log = JsonConvert.DeserializeObject<DataRoot>(logJson.data);
    fields.Add(log.column_id, log.value.column_settings.bccList   log.value.column_settings.ccPulse);
    fields.Add(log.pulse_name, log.value.column_settings.bccList   log.value.column_settings.ccPulse);
    fields.Add(log.previous_value.email, log.value.column_settings.bccList   log.value.column_settings.ccPulse);
    fields.Add(log.previous_textual_value, log.value.column_settings.bccList   log.value.column_settings.ccPulse);
}
  • Related