public NodeModel CreateNodeFromXml(XmlElement nodeElement, SaveContext context, ElementResolver resolver) { string assembly = ""; string function; var name = nodeElement.Attributes["nickname"].Value; FunctionDescriptor descriptor; Trace.Assert(nodeElement.Attributes != null, "nodeElement.Attributes != null"); if (nodeElement.Attributes["assembly"] == null) { assembly = DetermineAssemblyName(nodeElement); function = name.Replace(".get", "."); } else { string xmlSignature = nodeElement.Attributes["function"].Value; string hintedSigniture = libraryServices.GetFunctionSignatureFromFunctionSignatureHint(xmlSignature); if (hintedSigniture != null) { nodeElement.Attributes["nickname"].Value = libraryServices.NameFromFunctionSignature(xmlSignature); function = hintedSigniture; // if the node needs additional parameters, add them here libraryServices.AddAdditionalAttributesToNode(xmlSignature, nodeElement); libraryServices.AddAdditionalElementsToNode(xmlSignature, nodeElement); } else { function = xmlSignature; } var xmlAttribute = nodeElement.Attributes["assembly"]; if (xmlAttribute != null) { assembly = Uri.UnescapeDataString(xmlAttribute.Value); } } if ((context == SaveContext.File || context == SaveContext.Save || context == SaveContext.SaveAs) && !string.IsNullOrEmpty(assembly)) { var document = nodeElement.OwnerDocument; var docPath = Nodes.Utilities.GetDocumentXmlPath(document); assembly = Nodes.Utilities.MakeAbsolutePath(docPath, assembly); if (libraryServices.IsLibraryLoaded(assembly)) { descriptor = libraryServices.GetFunctionDescriptor(assembly, function); } else { // If the desired assembly is not loaded already. Check if it belongs to BuiltInFunctionGroup. if (libraryServices.IsFunctionBuiltIn(assembly, name)) { descriptor = libraryServices.GetFunctionDescriptor(function); } else { // If neither of these, Dynamo need to import the library. try { libraryServices.ImportLibrary(assembly); descriptor = libraryServices.GetFunctionDescriptor(assembly, function); } catch (LibraryLoadFailedException) { descriptor = libraryServices.GetFunctionDescriptor(function); } } } } else { descriptor = libraryServices.GetFunctionDescriptor(function); } if (null == descriptor) { var inputcount = DetermineFunctionInputCount(nodeElement); return(new DummyNode( inputcount, 1, name, nodeElement, assembly, DummyNode.Nature.Unresolved)); } DSFunctionBase result; if (descriptor.IsVarArg) { result = new DSVarArgFunction(descriptor); var akas = typeof(DSVarArgFunction).GetCustomAttribute <AlsoKnownAsAttribute>().Values; if (nodeElement.Name != typeof(DSVarArgFunction).FullName && akas.All(aka => aka != nodeElement.Name)) { VariableInputNodeController.SerializeInputCount( nodeElement, descriptor.Parameters.Count()); } } else { result = new DSFunction(descriptor); } result.Deserialize(nodeElement, context); // In case of input parameters mismatch, use default arguments for parameters that have one if (!descriptor.MangledName.EndsWith(function)) { string[] oldSignature = function.Split('@'); string[] inputTypes = oldSignature.Length > 1 ? oldSignature[1].Split(',') : new string[] {}; int i = 0, j = 0; foreach (var param in descriptor.InputParameters) { if (i >= inputTypes.Length || param.Item2 != inputTypes[i]) { result.InPorts[j].UsingDefaultValue = result.InPorts[j].DefaultValue != null; } else { i++; } j++; } } return(result); }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { NodeModel node = null; String typeName = String.Empty; String functionName = String.Empty; String assemblyName = String.Empty; var obj = JObject.Load(reader); Type type = null; try { type = Type.GetType(obj["$type"].Value <string>()); typeName = obj["$type"].Value <string>().Split(',').FirstOrDefault(); if (typeName.Equals("Dynamo.Graph.Nodes.ZeroTouch.DSFunction")) { // If it is a zero touch node, then get the whole function name including the namespace. functionName = obj["FunctionSignature"].Value <string>().Split('@').FirstOrDefault().Trim(); } // we get the assembly name from the type string for the node model nodes. else { assemblyName = obj["$type"].Value <string>().Split(',').Skip(1).FirstOrDefault().Trim(); } } catch (Exception e) { nodeFactory?.AsLogger().Log(e); } // If we can't find this type - try to look in our load from assemblies, // but only during testing - this is required during testing because some dlls are loaded // using Assembly.LoadFrom using the assemblyHelper - which loads dlls into loadFrom context - // dlls loaded with LoadFrom context cannot be found using Type.GetType() - this should // not be an issue during normal dynamo use but if it is we can enable this code. if (type == null && this.isTestMode == true) { List <Assembly> resultList; // This assemblyName does not usually contain version information... assemblyName = obj["$type"].Value <string>().Split(',').Skip(1).FirstOrDefault().Trim(); if (assemblyName != null) { if (this.loadedAssemblies.TryGetValue(assemblyName, out resultList)) { var matchingTypes = resultList.Select(x => x.GetType(typeName)).ToList(); type = matchingTypes.FirstOrDefault(); } } } // Check for and attempt to resolve an unknown type before proceeding if (type == null) { // Attempt to resolve the type using `AlsoKnownAs` var unresolvedName = obj["$type"].Value <string>().Split(',').FirstOrDefault(); Type newType; nodeFactory.ResolveType(unresolvedName, out newType); // If resolved update the type if (newType != null) { type = newType; } } // If the id is not a guid, makes a guid based on the id of the node var guid = GuidUtility.tryParseOrCreateGuid(obj["Id"].Value <string>()); var replication = obj["Replication"].Value <string>(); var inPorts = obj["Inputs"].ToArray().Select(t => t.ToObject <PortModel>()).ToArray(); var outPorts = obj["Outputs"].ToArray().Select(t => t.ToObject <PortModel>()).ToArray(); var resolver = (IdReferenceResolver)serializer.ReferenceResolver; string assemblyLocation = objectType.Assembly.Location; bool remapPorts = true; // If type is still null at this point return a dummy node if (type == null) { node = CreateDummyNode(obj, typeName, assemblyName, functionName, inPorts, outPorts); } // Attempt to create a valid node using the type else if (type == typeof(Function)) { var functionId = Guid.Parse(obj["FunctionSignature"].Value <string>()); CustomNodeDefinition def = null; CustomNodeInfo info = null; // Skip deserializing the Description Json property as the original one in dyf may // already be updated without syncing with the dyn bool isUnresolved = !manager.TryGetCustomNodeData(functionId, null, false, out def, out info); Function function = manager.CreateCustomNodeInstance(functionId, null, false, def, info); node = function; if (isUnresolved) { function.UpdatePortsForUnresolved(inPorts, outPorts); } } else if (type == typeof(CodeBlockNodeModel)) { var code = obj["Code"].Value <string>(); CodeBlockNodeModel codeBlockNode = new CodeBlockNodeModel(code, guid, 0.0, 0.0, libraryServices, ElementResolver); node = codeBlockNode; // If the code block node is in an error state read the extra port data // and initialize the input and output ports if (node.IsInErrorState) { List <string> inPortNames = new List <string>(); var inputs = obj["Inputs"]; foreach (var input in inputs) { inPortNames.Add(input["Name"].ToString()); } // NOTE: This could be done in a simpler way, but is being implemented // in this manner to allow for possible future port line number // information being available in the file List <int> outPortLineIndexes = new List <int>(); var outputs = obj["Outputs"]; int outputLineIndex = 0; foreach (var output in outputs) { outPortLineIndexes.Add(outputLineIndex++); } codeBlockNode.SetErrorStatePortData(inPortNames, outPortLineIndexes); } } else if (typeof(DSFunctionBase).IsAssignableFrom(type)) { var mangledName = obj["FunctionSignature"].Value <string>(); var lookupSignature = libraryServices.GetFunctionSignatureFromFunctionSignatureHint(mangledName) ?? mangledName; var functionDescriptor = libraryServices.GetFunctionDescriptor(lookupSignature); // Use the functionDescriptor to try and restore the proper node if possible if (functionDescriptor == null) { node = CreateDummyNode(obj, assemblyName, functionName, inPorts, outPorts); } else { if (type == typeof(DSVarArgFunction)) { node = new DSVarArgFunction(functionDescriptor); // The node syncs with the function definition. // Then we need to make the inport count correct var varg = (DSVarArgFunction)node; varg.VarInputController.SetNumInputs(inPorts.Count()); } else if (type == typeof(DSFunction)) { node = new DSFunction(functionDescriptor); } } } else if (type == typeof(DSVarArgFunction)) { var functionId = Guid.Parse(obj["FunctionSignature"].Value <string>()); node = manager.CreateCustomNodeInstance(functionId); } else if (type.ToString() == "CoreNodeModels.Formula") { node = (NodeModel)obj.ToObject(type); } else { node = (NodeModel)obj.ToObject(type); // if node is an customNode input symbol - assign the element resolver. if (node is Nodes.CustomNodes.Symbol) { (node as Nodes.CustomNodes.Symbol).ElementResolver = ElementResolver; } // We don't need to remap ports for any nodes with json constructors which pass ports remapPorts = false; } if (remapPorts) { RemapPorts(node, inPorts, outPorts, resolver, manager.AsLogger()); } // Cannot set Lacing directly as property is protected node.UpdateValue(new UpdateValueParams("ArgumentLacing", replication)); node.GUID = guid; // Add references to the node and the ports to the reference resolver, // so that they are available for entities which are deserialized later. serializer.ReferenceResolver.AddReference(serializer.Context, node.GUID.ToString(), node); foreach (var p in node.InPorts) { serializer.ReferenceResolver.AddReference(serializer.Context, p.GUID.ToString(), p); } foreach (var p in node.OutPorts) { serializer.ReferenceResolver.AddReference(serializer.Context, p.GUID.ToString(), p); } return(node); }