diff --git a/src/modules/Elsa.Expressions/Elsa.Expressions.csproj b/src/modules/Elsa.Expressions/Elsa.Expressions.csproj
index d696bff63..66d1a6e5e 100644
--- a/src/modules/Elsa.Expressions/Elsa.Expressions.csproj
+++ b/src/modules/Elsa.Expressions/Elsa.Expressions.csproj
@@ -15,6 +15,7 @@
+
diff --git a/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs b/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs
index f59e9861c..899a84ddc 100644
--- a/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs
+++ b/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs
@@ -102,15 +102,29 @@ public static class ObjectConverter
return jsonElement.Deserialize(targetType, serializerOptions);
}
- if (value is JsonNode jsonNode and not JsonArray) // If the value is a JsonNode, we can convert it to the target type. If it's a JsonArray, we let the enumerable conversion logic handle it.
+ if (value is JsonNode jsonNode)
{
- return underlyingTargetType switch
+ if (jsonNode is not JsonArray jsonArray)
{
- { } t when t == typeof(string) => jsonNode.ToString(),
- { } t when t == typeof(ExpandoObject) && jsonNode.GetValueKind() == JsonValueKind.Object => JsonSerializer.Deserialize(jsonNode.ToJsonString()),
- { } t when t != typeof(object) || converterOptions?.DeserializeJsonObjectToObject == true => jsonNode.Deserialize(targetType, serializerOptions),
- _ => jsonNode
- };
+ return underlyingTargetType switch
+ {
+ { } t when t == typeof(string) => jsonNode.ToString(),
+ { } t when t == typeof(ExpandoObject) && jsonNode.GetValueKind() == JsonValueKind.Object => JsonSerializer.Deserialize(jsonNode.ToJsonString()),
+ { } t when t != typeof(object) || converterOptions?.DeserializeJsonObjectToObject == true => jsonNode.Deserialize(targetType, serializerOptions),
+ _ => jsonNode
+ };
+ }
+
+ // Convert to target type if target type is an array or a generic collection.
+ if (targetType.IsArray || targetType.IsCollectionType())
+ {
+ // The element type of the source array is JsonObject. If the element type of the target array is Object then return the source array as an array of JsonObjects.
+ // Deserializing normally would return an array of JsonElement instead of JsonObject, but we want to keep JsonObject elements:
+ var targetElementType = targetType.IsArray ? targetType.GetElementType()! : targetType.GenericTypeArguments[0];
+
+ if (targetElementType != typeof(object))
+ return jsonArray.Deserialize(targetType, serializerOptions);
+ }
}
if (underlyingSourceType == typeof(string) && !underlyingTargetType.IsPrimitive && underlyingTargetType != typeof(object))
diff --git a/test/unit/Elsa.Workflows.Core.UnitTests/ObjectConversion/Person.cs b/test/unit/Elsa.Workflows.Core.UnitTests/ObjectConversion/Person.cs
new file mode 100644
index 000000000..b5583db8b
--- /dev/null
+++ b/test/unit/Elsa.Workflows.Core.UnitTests/ObjectConversion/Person.cs
@@ -0,0 +1,9 @@
+namespace Elsa.Workflows.Core.UnitTests.ObjectConversion
+{
+ public class Person
+ {
+ public double? Age { get; set; }
+
+ public string? Name { get; set; }
+ }
+}
diff --git a/test/unit/Elsa.Workflows.Core.UnitTests/ObjectConversion/Tests.cs b/test/unit/Elsa.Workflows.Core.UnitTests/ObjectConversion/Tests.cs
index 6525f5d0e..c245cb5cc 100644
--- a/test/unit/Elsa.Workflows.Core.UnitTests/ObjectConversion/Tests.cs
+++ b/test/unit/Elsa.Workflows.Core.UnitTests/ObjectConversion/Tests.cs
@@ -283,4 +283,21 @@ public class Tests
Assert.Equal("Bob", secondElement["name"]?.ToString());
Assert.Equal("25", secondElement["age"]?.ToString());
}
+
+ [Fact]
+ public void ConvertFrom_JsonArrayToArrayOfComplextType_ReturnsArrayOfComplexType()
+ {
+ // Arrange
+ var jsonArrayString = "[{\"name\":\"Alice\",\"age\":30},{\"name\":\"Bob\",\"age\":25}]";
+ var options = new ObjectConverterOptions();
+
+ // Act
+ var result = jsonArrayString.ConvertTo(options);
+
+ // Assert
+ Assert.NotNull(result);
+ Assert.Equal(2, result.Length);
+ Assert.Equal("Alice", result[0].Name);
+ Assert.Equal("Bob", result[1].Name);
+ }
}
\ No newline at end of file