Duplicate output port in custom node error

Hi

I am getting a problem with the view template node from Archilab @Konrad_K_Sobon. Before I run it, it displays fine. After I run it, I get a duplicate output port and an error:

Warning: Dictionary.ByKeysValues operation failed.
An element with the same key but a different value already exists. Key: viewTemplate

I think there might be a dependancy conflict as I have this issue:

@john_pierson could Monocle be causing this?

Running Revit 2018 and Dynamo 2.0.3. Here are the packages installed:


I have seen this when the version of the package is not compatible / meant for the version of Dynamo you are running, and most often the package is older. I would try to install a newer version of archi-lab and see since the 2018.13.13 is quite a ways down the list for this package.

1 Like

Thanks @SeanP.

I think it might be the other way around though - using a newer package on Revit 2018. Maybe I need to use an older version of Archilab, like 2018.13.1.3 instead of 2019.2.6, if I’m still on Revit 2018.

Hmm. Monocle shouldn’t be causing duplicate output ports. I do see that you have a fairly old version of Archi-Lab that is most likely not built for Dynamo 2.0. I would try to get that updated to the latest version of 2019.2.26 and see if it fixes.

*edit: didn’t see the other replies because I replied from email. lol

Definitely get that package updated and see if it helps.

For monocle’s error that is popping up. That’s different and related to Dynamo loading an older version of a DLL that I also used. I’ll see if I can get that revised here soon. (Unfortunately that means I have to use an old version of that dependency too.)

1 Like

@Paul_Wintour the issue is just what @SeanP mentioned. You are using the version of the package that was built against the Dynamo 1.3 which didn’t use the new JSON based schema, and doesn’t have a proper constructors.

Now, I see that you went with that version because you want to use it with Revit 2018, but in this case I think its safe to use versions starting with 2019 (built against Revit 2019 API). Why? Because if there is a node in my package that uses any of the new APIs from Revit, it would simply not work, but rest of the package will work just fine, and they were all built against Dynamo 2.0 and higher so no duplicate ports there. You might get a warning that my package is looking for Revit 2019 dlls, but again, if Revit 2018 dlls are available, then it should all work, unless API specific to 2019 is used by a node.

So, please always use the LATEST package. Revit API version it was built against is a smaller concern than version of Dynamo you are on.

Cheers!

4 Likes

Thanks @Konrad_K_Sobon & @SeanP. I though I had the latest but that was for the Dynamo 2.1 library, not Dynamo 2.0 library. Updating fixed the issue. Thanks again

I have this trouble trying to make one NodeModel node (a Enum Drop-down node). Dou you know the way to fix that ?

I’m using Dynamo 2.10.1.

Make sure you add the JSON constructor.

1 Like

Thanks for your answer but it seems I’m in trouble anyway, even using [Json Constructor]. I tried to use it and still not works.

The question is that one of my Nuget packages (GeoJSON.Net) needs to use Newtonsoft >= 10

and according what I seen in Update nuspec to include Newtonsoft.Json by QilongTang · Pull Request #8860 · DynamoDS/Dynamo (github.com) DynamoCore needs to use Newtonsoft 8.0.3. which is installed automatically with DynamoCore Nuget Package.

If there are any solution to make this work, I will be very happy if you know how.

Thank you one more time.

Try, not shipping json net 10 in your package. The API is likely the same.

1 Like

Since the GeoJSON.Net package is open source, I created a new onBIM.GeoJSON.NET project in my solution and added all the code from the original. In this new project I installed NewtonSoft 8.0.3 and the project was compiled normally.

However, as you can see in the image below, the problem of duplicated ports continues, but now the Warning is different. However, I still don’t understand why this is still happening since all projects within my solution have Newtonsoft 8.0.3 installed.

The following image shows the files delivered with my package.

image

My solution structure.

image

From my Solution’s Manage Nuget packages window you can see how Newtonsoft is used from each project.

you’ll have to share a repro project - github repo usually works wells.

1 Like

Finally !!!

After a hellish dll saga and a “few” hours of headache, everything worked fine now.

Main actions that were taken:

  1. I copied all the code from the GeoJSON.Net package to my project in order to eliminate the dependency on a Newtonsoft version not compatible with Dynamo.

  2. Instead of using an abstract class to implement my NodeModel DropDown, I implemented it directly.
    The idea of having an abstract class was to generalize the construction of other DropDowns, but it didn’t work out because it was necessary to pass the Enum Type and Parse Func as parameters. This caused abnormal behavior where DropDown only worked the second time the file was opened. Which then made sense to me, because it seems that in the first round the node was created by one constructor, then by another.

  3. I created [JsonConstructor] as recommended.

Old code:

using Dynamo.Graph.Nodes;
using Newtonsoft.Json;
using System;

namespace NodeModels
{
    [NodeName("Elevation Types")]
    [NodeDescription("onBIM nodes GIS Elevation types to be used in GeoJSON geometry conversion to Dynamo")]
    [NodeCategory("onBIM Nodes.GIS")]
    [OutPortNames("ElevationType")]
    [OutPortTypes("onBIMNodes.GIS.ElevationType")]
    [OutPortDescriptions("Selected ElevationType")]
    [IsDesignScriptCompatible]
    public class ElevationTypesDropDown : CustomGenericEnumerationDropDown //old abstract class
    {
        public ElevationTypesDropDown() : base() 
        {
            EnumerationType = typeof(onBIMNodes.GIS.ElevationType);
            EnumParseFunction = NodeModelsFunctions.ElevationTypesDropDownFunctions.ParseElevationType;
        }
    }
}

new code:

using CoreNodeModels;
using Dynamo.Graph.Nodes;
using Dynamo.Utilities;
using Newtonsoft.Json;
using ProtoCore.AST.AssociativeAST;
using System;
using System.Collections.Generic;
using System.Linq;

namespace NodeModels
{
    /// <summary>
    /// Generic UI Dropdown node baseclass for Enumerations.
    /// This class populates a dropdown with all enumeration values of the specified type.
    /// </summary>
    [NodeName("Elevation Types")]
    [NodeDescription("onBIMNodes GIS Elevation types to be used in GeoJSON geometry conversion to Dynamo")]
    [NodeCategory("onBIM Nodes.GIS")]
    [OutPortDescriptions("Selected ElevationType")]
    [IsDesignScriptCompatible]
    public class ElevationTypesDropDown : DSDropDownBase
    {
        public ElevationTypesDropDown() : base("ElevationType") { }

        [JsonConstructor]
        public ElevationTypesDropDown(
            IEnumerable<PortModel> inPorts, 
            IEnumerable<PortModel> outPorts
        ) : base("ElevationType", inPorts,outPorts) { }

        protected override CoreNodeModels.DSDropDownBase.SelectionState PopulateItemsCore(string currentSelection)
        {
            PopulateDropDownItems();
            return SelectionState.Restore;
        }

        /// <summary>
        /// Populate Items in Dropdown menu
        /// </summary>
        public void PopulateDropDownItems()
        {
            Type EnumerationType = typeof(onBIMNodes.GIS.ElevationType);

            // Clear the dropdown list
            Items.Clear();

            // Get all enumeration names and add them to the dropdown menu
            foreach (string name in Enum.GetNames(EnumerationType))
            {
                Items.Add(new CoreNodeModels.DynamoDropDownItem(name, Enum.Parse(EnumerationType, name)));
            }

            Items = Items.OrderBy(x => x.Name).ToObservableCollection();

            // Prevent node to raise a Warning when Dynamo script is in Automatic mode
            // by Selecting the list first item
            SelectedIndex = 0;
        }

        /// <summary>
        /// Assign the selected Enumeration value to the output
        /// </summary>
        public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes)
        {
            Func<string, object> EnumParseFunction = NodeModelsFunctions.ElevationTypesDropDownFunctions.ParseElevationType;

            // get the selected item name    
            var stringNode = AstFactory.BuildStringNode((string)Items[SelectedIndex].Name);
            var args = new List<AssociativeNode>();
            args.Add(stringNode);

            var functionCall = AstFactory.BuildFunctionCall(EnumParseFunction, args);

            // assign the selected name to an actual enumeration value
            var assign = AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), functionCall);

            // return the enumeration value
            return new List<AssociativeNode> { assign };
        }

    }
}

Thank you so much guys for your help.