Zero Touch Node JSON issue

Hi all!

I am trying to create a zero-touch node with C# and Visual Studio.

This ZTN has to read info contained within a Dictionary as input after parsing from a JSON file. Please find a screenshot where I show not only the input but also the warning I get from the custom node:

The issue comes when trying to access to the Dictionary key called “Points”. If I create a Python node to doublecheck the data type it seems it has something to do with Newtonsoft.


My first question is, if I already parsed the JSON file, why I am still getting JSON types within my dictionary?
On the other hand, this is my C# code where I am unable to access to the “Points” key value. I tried many alternatives such as JToken, JArray, etc with no success:

public static Dictionary<string, object> ConvertGeometriesFromPoints(Dictionary<string, object> myDict)
        {
            foreach (string key in myDict.Keys)
            {
                if (key == "Points" && myDict[key] is List<Dictionary<string, object>>)
                {
                    try
                    {
                        List<Point> points = new List<Point>();

                        foreach (Dictionary<string, object> dict in (List<Dictionary<string, object>>)myDict[key])
                        {
                            double x = Convert.ToDouble(dict["X"]);
                            double y = Convert.ToDouble(dict["Y"]);
                            Point point = Point.ByCoordinates(x, y);
                            points.Add(point);
                        }

                        PolyCurve polycurve = PolyCurve.ByPoints(points);
                        myDict[key] = polycurve;
                    }
                    catch (Exception ex)
                    {
                        myDict[key] = $"Error when creating PolyCurve: {ex.Message}";
                    }
                }
                else if (key == "Points")
                {
                    myDict[key] = "Error when accessing Point list";
                }
            }
            return myDict;
        }

I also attach the JSON file used as input and the DYN file.
JSON.txt (4.9 KB)

cc.dyn (11.9 KB)

Thank you!

The loop over your myDict.Keys should be copied to another list.

public static Dictionary<string, object> ConvertGeometriesFromPoints(Dictionary<string, object> myDict)
{
   var keys = new List<string>(myDict.Keys);

   foreach (string key in keys)
   {
       if (key == "Points" && myDict[key] is List<Dictionary<string, object>>)
       {
           try
           {
               List<Point> points = new List<Point>();

               foreach (Dictionary<string, object> dict in (List<Dictionary<string, object>>)myDict[key])
               {
                  double x = Convert.ToDouble(dict["X"]);
                  double y = Convert.ToDouble(dict["Y"]);
                  Point point = Point.ByCoordinates(x, y);
                  points.Add(point);
               }

               PolyCurve polycurve = PolyCurve.ByPoints(points);
               myDict[key] = polycurve;
           }
           catch (Exception ex)
           {
               myDict[key] = $"Error when creating PolyCurve: {ex.Message}";
           }
       }
       else if (key == "Points")
       {
           myDict[key] = "Error when accessing Point list";
       }
   }
   return myDict;
}

Hi Deniz, thank you so much for your reply.

Unfortunately, this is not working. You´re right that I need to store all the keys in a list or use the method.ToList() to loop through all of them. But after that line of code, it seems here is the issue:

if (key == "Points" && myDict[key] is List<Dictionary<string, object>>)

It seems my “Points” list *at least shown as that in Dynamo( is not a list indeed because my code is jumping straight into the debug line:

else if (key == "Points")
                {
                    myDict[key] = "Error when accessing Point list";
                }


As I said in my first comment, it seems that “Points” list is not a type list itself as this Python node shows:

In fact, if I get rid of the statement:

&& myDict[key] is List<Dictionary<string, object>>)

I get into the foreach loop but all of a sudden now the issue is with this accessing line of code:

foreach (Dictionary<string, object> dict in (List<Dictionary<string, object>>)myDict[key])

Again, because it seems myDict[“Points”] is a data type

System.Linq.Enumerable+WhereSelectEnumerableIterator`2[Newtonsoft.Json.Linq.JToken,System.Object]

Thank you.

A test using directly Newtonsoft.Json (which available in Current Domain Application)

using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Revit.GeometryConversion;
using DS = Autodesk.DesignScript.Geometry;

namespace Custom.Element
{
    public class SimpleFonction
    {
        private SimpleFonction()
        {
        }
        public static List<object> ConvertGeometriesFromJson(string filepath)
        {
            var data = new List<object>();
            try
            {
                // Read the JSON file and parse it into a JArray.
                JArray jarray = JArray.Parse(File.ReadAllText(filepath));
                // Iterate through each JObject in the JArray.
                foreach (JObject jobject in jarray)
                {
                    JArray points = (JArray)jobject["Points"];
                    // Create two points using the extracted coordinates.
                    double x1 = (double)points[0]["X"];
                    double y1 = (double)points[0]["Y"];
                    double x2 = (double)points[1]["X"];
                    double y2 = (double)points[1]["Y"];
                    DS.Point pt1 = DS.Point.ByCoordinates(x1, y1, 0);
                    DS.Point pt2 = DS.Point.ByCoordinates(x2, y2, 0);
                    // Add a line created from the two points to the data list.
                    data.Add(DS.Line.ByStartPointEndPoint(pt1, pt2));
                }
                
                return data;
            }
            catch (Exception ex)
            {

                return new List<object> { ex.ToString() };
            }

        }
    }
}
1 Like

Maybe you can show us your full zero-touch node code first, then we will be able to help you more :slight_smile, but judging from your error message, the first error gotta do with you manipulating a collection while looping through it…
And the second error you showed on your image, or at least half of it, shows that that is some casting error. You are trying to cast from some object to PolyCurve, which is “illegal” in that case and hence the error…
The fact that you are getting an Iterator with JToken means you are using “object” or “dynamic” as your deserialization type. I would avoid that and use something easier to understand for eg. List<type>/Dictionary<string, type> or even better if you know how to create your class and deserialize to it :smiley:

        public static List<MyObject> Test(string FilePath)
        {
            string jsonString = File.ReadAllText(FilePath);
            return Newtonsoft.Json.JsonConvert.DeserializeObject<List<MyObject>>(jsonString);
        }

        public class MyObject
        {
            public string Key { get; set; }
            public string ID { get; set; }
            public int Group { get; set; }
            public int Mark { get; set; }
            public List<MyPoint> Points { get; set; }
            public string Key2 { get; set; }
        }

        public class MyPoint
        {
            public double X { get; set; }
            public double Y { get; set; }
        }

Something like that