-1

I could use some help looping through the following JSon:

 string jsonobj = "[{'LastTighteningResultDataRev3': 'Header', 'Attribute': ['Length','1','4']},
    {'LastTighteningResultDataRev3': 'Header', 'Attribute': ['MID','5','4']},
    {'LastTighteningResultDataRev3': 'Header', 'Attribute': ['REV','9','3']},
    {'LastTighteningResultDataRev3': 'DataFields', 'Attribute': ['CellID','21','2','23','3']},
    {'LastTighteningResultDataRev3': 'DataFields', 'Attribute': ['ChannelID','27','2','29','2']}]";

I deserialize the JSon to a dynamic:

   #region "Parse Data Schema"
   var tempObj = new[] { new { LastTighteningResultDataRev3 = "", Attribute = new List<string>() } };
   var deserializedObject = JsonConvert.DeserializeAnonymousType(jsonobj, tempObj);
   #endregion

Here the code that I went with in the end:

     #region "LoadACOPLastTighteningResultDataGLRepository using the Data Schema Information"
        deserializedObject.ToList().ForEach(attrs =>
        {
            #region "InitACOPLastTighteningResultDataProperties"
                                        acoplasttighteningresultdatacs.InitACOPLastTighteningResultDataProperties();
            #endregion
            #region "Load Attribute Parse Information from Data Schema Information
            acoplasttighteningresultdatacs.p_Attribute = attrs.Attribute[0];                                    
            acoplasttighteningresultdatacs.p_AttributeIDStartPosition = attrs.Attribute[1];                                    
            acoplasttighteningresultdatacs.p_AttributeIDLength = attrs.Attribute[2];
            if (attrs.LastTighteningResultDataRev3 == "DataFields") acoplasttighteningresultdatacs.p_AttributeValueStartPosition = attrs.Attribute[3];
            if (attrs.LastTighteningResultDataRev3 == "DataFields") acoplasttighteningresultdatacs.p_AttributeValueStartLength = attrs.Attribute[4];
            #region "Load attribute ID values from controller response mesage"
            acoplasttighteningresultdatacs.p_AttributeIDValue = (attrs.LastTighteningResultDataRev3 == "DataFields") ?
testrequestresponseinfocs.p_TestResult.Substring(Convert.ToInt16(acoplasttighteningresultdatacs.p_AttributeIDStartPosition) - 1,
    Convert.ToInt16(acoplasttighteningresultdatacs.p_AttributeIDLength)) : null;
           #endregion
           #region "Load attribute values from controller response mesage"
           if (attrs.LastTighteningResultDataRev3 == "Header") 
           acoplasttighteningresultdatacs.p_AttributeValue = 
    testrequestresponseinfocs.p_TestResult.Substring(Convert.ToInt16(acoplasttighteningresultdatacs.p_AttributeIDStartPosition) - 1,
        Convert.ToInt16(acoplasttighteningresultdatacs.p_AttributeIDLength));
           if (attrs.LastTighteningResultDataRev3 == "DataFields")
     acoplasttighteningresultdatacs.p_AttributeValue = 
    testrequestresponseinfocs.p_TestResult.Substring(Convert.ToInt16(acoplasttighteningresultdatacs.p_AttributeValueStartPosition) - 1,
                                                                                                 Convert.ToInt16(acoplasttighteningresultdatacs.p_AttributeValueStartLength));
          #endregion
      #endregion
      if (acoplasttighteningresultdatacs.LoadACOPLastTighteningResultDataGLRepository()) return;
      });
     #endregion

I didn't elect to go with this code, but if you need to limit the selection to the "DataFields" this code will work:

     var deserializedList = JsonConvert.DeserializeAnonymousType(LastTighteningResultDT.Rows[0]["DataSchema"].ToString(), tempObj).ToList();

     deserializedList.Where(x => x.LastTighteningResultDataRev3 =="DataFields").Select(y => y.Attribute).ToList().ForEach(attrs =>
     {
        {

          acoplasttighteningresultdatacs.p_Attribute = attrs[0];
          acoplasttighteningresultdatacs.p_AttributeIDStartPosition = attrs[1];
          acoplasttighteningresultdatacs.p_AttributeIDLength = attrs[2];
          #region "Load attribute values from controller response mesage"
          acoplasttighteningresultdatacs.p_AttributeIDValue =

testrequestresponseinfocs.p_TestResult.Substring(Convert.ToInt16(acoplasttighteningresultdatacs.p_AttributeIDStartPosition) - 1, Convert.ToInt16(acoplasttighteningresultdatacs.p_AttributeIDLength)); #endregion acoplasttighteningresultdatacs.p_AttributeValueStartPosition = attrs[3]; acoplasttighteningresultdatacs.p_AttributeValueStartLength = attrs[4]; #region "Load attribute values from controller response mesage" acoplasttighteningresultdatacs.p_AttributeValue = testrequestresponseinfocs.p_TestResult.Substring(Convert.ToInt16(acoplasttighteningresultdatacs.p_AttributeValueStartPosition) - 1, Convert.ToInt16(acoplasttighteningresultdatacs.p_AttributeValueStartLength)); #endregion

          if (acoplasttighteningresultdatacs.LoadACOPLastTighteningResultDataGLRepository()) return;
      }
    });

Needed to retrieve the attribute information for the business rules; so, I loaded the last tightening result data repository into a dictionary, which allowed easy look of the attribute info. This way if the schema info changes the solution will still be able to find the attribute info. (I.E. TighteningStatus). It will find the last tightening result data for all the business rule attributes and all have to pass.

    #region "Static ACOPLastTighteningResultDataCS Dictionary"
    public static Dictionary<int, ACOPLastTighteningResultDataCS> ACOPLastTighteningResultDataDictionary = new Dictionary<int, ACOPLastTighteningResultDataCS>();
    #endregion   

    #region "Static ACOPLastTighteningResultDataRepositoryForAttribute"
    public static List<ACOPLastTighteningResultDataCS> ACOPLastTighteningResultDataRepositoryForAttribute = new List<ACOPLastTighteningResultDataCS>();
    #endregion

   #region "Validate by Business Rule Type"
            bool ValidatedSW = false;
            switch (Convert.ToInt32(BusinessRuleInfoDT.Rows[0]["BusinessRuleTypeInfoID"].ToString()))
            {
                case ((int)BusinessRuleTypes.Length):
                    {
                       if (gvTestActions.Rows[gvTestActions.CurrentRow.Index].Cells[(int)gvCols.ScannedInValue].Value.ToString().Trim().Length == Convert.ToInt32(BusinessRuleInfoDT.Rows[0]["Value"])) ValidatedSW = true;
                       break;
                    }
                case ((int)BusinessRuleTypes.Contains):
                    {
                        ValidatedSW = false;
                        break;
                    }
                case ((int)BusinessRuleTypes.Compare):
                    {
                        if (!(ACOPLastTighteningResultDataCS.LoadACOPLastTighteningResultDataDictionary())) break;
                        if (!(ACOPLastTighteningResultDataCS.GetACOPLastTighteningResultDataByAttributeID(Convert.ToInt32(BusinessRuleInfoDT.Rows[0]["AttributeID"])))) return;
                        if (Convert.ToInt32(ACOPLastTighteningResultDataCS.ACOPLastTighteningResultDataRepositoryForAttribute[0].p_AttributeValue) == Convert.ToInt32(BusinessRuleInfoDT.Rows[0]["Value"])) ValidatedSW = true;    
                        break;
                    }
                case ((int)BusinessRuleTypes.ValidRange):
                    {
                        ValidatedSW = false;
                        break;
                    }
                case ((int)BusinessRuleTypes.Authorize):
                    {
                        ValidatedSW = false;
                        break;
                    }
            }

Here's the load dictionary for repository code:

        #region "LoadACOPLastTighteningResultDataDictionary"
        public static bool LoadACOPLastTighteningResultDataDictionary()
        {
            try
            {
                #region "Clear dictionary"
                if (ACOPLastTighteningResultDataDictionary.Count > 0) ACOPLastTighteningResultDataDictionary.Clear();
                #endregion
                #region "Load dictionary from generic list class"
                ACOPLastTighteningResultDataDictionary = ACOPLastTighteningResultDataGLRepository.Where(x => x.p_AttributeIDValue != null).ToDictionary(p => Convert.ToInt32(p.p_AttributeIDValue), p => p);
                #endregion

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        #endregion

Here is the get attribute id from dictionary method. I load it to a static generic list, so that I can access the values on the UI thread:

#region "GetACOPLastTighteningResultDataByAttributeID"
        public static bool GetACOPLastTighteningResultDataByAttributeID(int AttributeID)
        {
            try
            {
                ACOPLastTighteningResultDataCS acopLastTighteningResultDataGLRepository;
                if (!(ACOPLastTighteningResultDataDictionary.TryGetValue(AttributeID, out acopLastTighteningResultDataGLRepository))) return false;
                ACOPLastTighteningResultDataRepositoryForAttribute.Add(new ACOPLastTighteningResultDataCS
                {
                    p_AttributeIDStartPosition = acopLastTighteningResultDataGLRepository.p_AttributeIDStartPosition,
                    p_AttributeIDLength = acopLastTighteningResultDataGLRepository.p_AttributeIDLength,
                    p_Attribute = acopLastTighteningResultDataGLRepository.p_Attribute,
                    p_AttributeIDValue = acopLastTighteningResultDataGLRepository.p_AttributeIDValue,
                    p_AttributeValue = acopLastTighteningResultDataGLRepository.p_AttributeValue,
                    p_AttributeValueStartPosition = acopLastTighteningResultDataGLRepository.p_AttributeValueStartPosition,
                    p_AttributeValueStartLength = acopLastTighteningResultDataGLRepository.p_AttributeValueStartLength
                });
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        #endregion
5
  • Why are you using a dynamic? Is this data structure likely to change? All the objects right now have the same fields. You should probably be using a model and deserializing to a type Commented Jan 9, 2020 at 14:39
  • foreach (dynamic item in jsondynamic) works, if you really want it to be dynamic. Commented Jan 9, 2020 at 14:43
  • Does this answer your question? How to iterate over an array of dynamic type in C# 4.0? Commented Jan 9, 2020 at 14:46
  • 1
    What help do you need? What are you looking to do in each loop? Commented Jan 9, 2020 at 14:47
  • I won't go with Json is invalid. string delimiter is " not '. It's non standard. But with JsonTextWriter.QuoteChar you should be able to parse it with no issue. Commented Jan 9, 2020 at 14:56

2 Answers 2

1

You can use Newtonsoft's JsonConvert.DeserializeAnonymousType for this

            string jsonobj = @"[{'LastTighteningResultDataRev3': 'Header', 'Attribute': ['Length','1','4']},
                { 'LastTighteningResultDataRev3': 'Header', 'Attribute': ['MID','5','4']
                },
                {'LastTighteningResultDataRev3': 'Header', 'Attribute': ['REV','9','3']
            },
                {'LastTighteningResultDataRev3': 'DataFields', 'Attribute': ['CellID','21','2','23','3']},
                {'LastTighteningResultDataRev3': 'DataFields', 'Attribute': ['ChannelID','27','2','29','2']}]";


        var tempObj = new[] {
            new {
                LastTighteningResultDataRev3 = "",
                Attribute = new List<string>()
            }
        };

        var deserializedObject = JsonConvert.DeserializeAnonymousType(jsonobj, tempObj);

        deserializedObject.ToList().ForEach(x => {
            //you can access x.LastTighteningResultDataRev3
            //you can access x.attributes
            x.Attribute.ForEach(a =>
            {                    
                //loop through attributes
            });
        });
Sign up to request clarification or add additional context in comments.

3 Comments

This worked for me! Not sure if it's the best solution for my circumstances, but grateful for the help.
While looping through the attributes how can I filter between the headers and datafields?
if you want to filter between headers and datafields then maybe you can do something like this: var deserializedList = JsonConvert.DeserializeAnonymousType(jsonobj, tempObj).ToList(); deserializedList.Where(x => x.LastTighteningResultDataRev3 == "Header").Select(y => y.Attribute).ToList() .ForEach(attrs => { //now you can loop through header attributes only attrs.ForEach(attr => { Console.WriteLine(attr); }); });
0

If you REALLY need it to be dynamic then use Pavel's answer.

If not I would suggest the following:

public class LastTighteningResultData {
    public string LastTighteningResultDataRev3 {get;set;}
    public IEnumerable<string> Attribute {get;set;}
}

var data = JsonConvert.DeserializeObject<LastTighteningResultData[]>(jsonobj);

foreach (var resultData in data) 
{
    // do stuff here with resultData.LastTighteningResultDataRev3 & resultData.Attribute
}

By strongly typing your data you make everything a lot easier for yourself.

2 Comments

Receive the following error msg: foreach statement cannot operate on variables of type object because object does not contain a public instance definition of GetEnumerator. Please advise on how to resolve this issue.
Sorry, I missed something in the example. I shall update it.You need to use the generic version of DeserializeObject and specify the type you wish to deserialize too. JsonConvert.DeserializeObject<LastTighteningResultData[]>(jsonobj);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.