diff --git a/src/modules/Elsa.Workflows.Core/Services/WorkflowBuilderFactory.cs b/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilderFactory.cs
similarity index 59%
rename from src/modules/Elsa.Workflows.Core/Services/WorkflowBuilderFactory.cs
rename to src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilderFactory.cs
index 835a48be2..257d095e8 100644
--- a/src/modules/Elsa.Workflows.Core/Services/WorkflowBuilderFactory.cs
+++ b/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilderFactory.cs
@@ -1,10 +1,17 @@
using Elsa.Workflows.Core.Contracts;
-namespace Elsa.Workflows.Core.Services;
+namespace Elsa.Workflows.Core.Builders;
+///
public class WorkflowBuilderFactory : IWorkflowBuilderFactory
{
private readonly Func _factory;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
public WorkflowBuilderFactory(Func factory) => _factory = factory;
+
+ ///
public IWorkflowBuilder CreateBuilder() => _factory();
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowBuilderFactory.cs b/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowBuilderFactory.cs
index 1f2dd1140..20f9fa82b 100644
--- a/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowBuilderFactory.cs
+++ b/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowBuilderFactory.cs
@@ -1,6 +1,13 @@
namespace Elsa.Workflows.Core.Contracts;
+///
+/// A factory of workflow builders.
+///
public interface IWorkflowBuilderFactory
{
+ ///
+ /// Creates a new workflow builder.
+ ///
+ /// A new workflow builder.
IWorkflowBuilder CreateBuilder();
}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs
index c577eed53..ac1637aa1 100644
--- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs
+++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/VariableConverter.cs
@@ -25,7 +25,7 @@ public class VariableConverter : JsonConverter
}
///
- public override Variable? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override Variable Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var newOptions = new JsonSerializerOptions(options);
newOptions.Converters.Add(new JsonPrimitiveToStringConverter());
@@ -42,17 +42,20 @@ public class VariableConverter : JsonConverter
JsonSerializer.Serialize(writer, model, options);
}
- private Variable? Map(VariableModel source)
+ private Variable Map(VariableModel source)
{
+ var typeName = source.TypeName;
+
if (string.IsNullOrWhiteSpace(source.TypeName))
- return null;
+ typeName = _wellKnownTypeRegistry.GetAliasOrDefault(typeof(object));
- if (!_wellKnownTypeRegistry.TryGetTypeOrDefault(source.TypeName, out var type))
- return null;
+ if (!_wellKnownTypeRegistry.TryGetTypeOrDefault(typeName, out var type))
+ type = typeof(object);
var variableGenericType = typeof(Variable<>).MakeGenericType(type);
var variable = (Variable)Activator.CreateInstance(variableGenericType)!;
+ // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
variable.Id = source.Id ?? Guid.NewGuid().ToString("N"); // Temporarily assign a new ID if the source doesn't have one.
variable.Name = source.Name;
diff --git a/src/modules/Elsa.Workflows.Core/Services/JsonPayloadSerializer.cs b/src/modules/Elsa.Workflows.Core/Services/JsonPayloadSerializer.cs
index e221f76e4..0a25ff553 100644
--- a/src/modules/Elsa.Workflows.Core/Services/JsonPayloadSerializer.cs
+++ b/src/modules/Elsa.Workflows.Core/Services/JsonPayloadSerializer.cs
@@ -53,8 +53,9 @@ public class JsonPayloadSerializer : IPayloadSerializer
options.Converters.Add(new JsonStringEnumConverter());
options.Converters.Add(JsonMetadataServices.TimeSpanConverter);
- options.Converters.Add(new PolymorphicObjectConverterFactory());
+ options.Converters.Add(GetService());
options.Converters.Add(GetService());
+ options.Converters.Add(GetService());
return options;
}
diff --git a/test/integration/Elsa.IntegrationTests/Serialization/VariableTypes/Models.cs b/test/integration/Elsa.IntegrationTests/Serialization/VariableTypes/Models.cs
new file mode 100644
index 000000000..07ec234b3
--- /dev/null
+++ b/test/integration/Elsa.IntegrationTests/Serialization/VariableTypes/Models.cs
@@ -0,0 +1,7 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using Elsa.Workflows.Core.Models;
+
+namespace Elsa.IntegrationTests.Serialization.VariableTypes;
+
+internal record VariablesContainer(ICollection Variables);
\ No newline at end of file
diff --git a/test/integration/Elsa.IntegrationTests/Serialization/VariableTypes/Tests.cs b/test/integration/Elsa.IntegrationTests/Serialization/VariableTypes/Tests.cs
new file mode 100644
index 000000000..3b0b4ffa1
--- /dev/null
+++ b/test/integration/Elsa.IntegrationTests/Serialization/VariableTypes/Tests.cs
@@ -0,0 +1,47 @@
+using System.Collections.ObjectModel;
+using System.Linq;
+using Elsa.Testing.Shared;
+using Elsa.Workflows.Core.Contracts;
+using Elsa.Workflows.Core.Models;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Elsa.IntegrationTests.Serialization.VariableTypes;
+
+public class Tests
+{
+ private readonly IPayloadSerializer _payloadSerializer;
+
+ public Tests(ITestOutputHelper testOutputHelper)
+ {
+ var services = new TestApplicationBuilder(testOutputHelper).Build();
+ _payloadSerializer = services.GetRequiredService();
+ }
+
+ [Fact(DisplayName = "Variable types remain intact after serialization")]
+ public void Test1()
+ {
+ // Create collection of variables to serialize.
+ var variables = new Collection();
+ var model = new VariablesContainer(variables);
+
+ // Create a typed variable.
+ var variable = new Variable();
+
+ // Add variable to collection.
+ variables.Add(variable);
+
+ // Serialize collection.
+ var json = _payloadSerializer.Serialize(model);
+
+ // Deserialize collection.
+ var deserializedModel = _payloadSerializer.Deserialize(json);
+
+ // Get the first variable.
+ var deserializedVariable = deserializedModel.Variables.First();
+
+ // Assert that the variable is of the correct type.
+ Assert.IsType>(deserializedVariable);
+ }
+}
\ No newline at end of file
diff --git a/test/integration/Elsa.IntegrationTests/Serialization/VariableTypes/Workflows.cs b/test/integration/Elsa.IntegrationTests/Serialization/VariableTypes/Workflows.cs
new file mode 100644
index 000000000..bed83a323
--- /dev/null
+++ b/test/integration/Elsa.IntegrationTests/Serialization/VariableTypes/Workflows.cs
@@ -0,0 +1,14 @@
+using Elsa.Workflows.Core.Abstractions;
+using Elsa.Workflows.Core.Activities;
+using Elsa.Workflows.Core.Contracts;
+using Elsa.Workflows.Runtime.Activities;
+
+namespace Elsa.IntegrationTests.Serialization.VariableTypes;
+
+class SampleWorkflow : WorkflowBase
+{
+ protected override void Build(IWorkflowBuilder workflow)
+ {
+ workflow.WithVariable();
+ }
+}
\ No newline at end of file