Fix variable type serialization

This commit is contained in:
Sipke Schoorstra 2023-04-28 14:31:38 +02:00
parent c31d5323a5
commit a67361c6ae
7 changed files with 93 additions and 7 deletions

View file

@ -1,10 +1,17 @@
using Elsa.Workflows.Core.Contracts;
namespace Elsa.Workflows.Core.Services;
namespace Elsa.Workflows.Core.Builders;
/// <inheritdoc />
public class WorkflowBuilderFactory : IWorkflowBuilderFactory
{
private readonly Func<IWorkflowBuilder> _factory;
/// <summary>
/// Initializes a new instance of the <see cref="WorkflowBuilderFactory"/> class.
/// </summary>
public WorkflowBuilderFactory(Func<IWorkflowBuilder> factory) => _factory = factory;
/// <inheritdoc />
public IWorkflowBuilder CreateBuilder() => _factory();
}

View file

@ -1,6 +1,13 @@
namespace Elsa.Workflows.Core.Contracts;
/// <summary>
/// A factory of workflow builders.
/// </summary>
public interface IWorkflowBuilderFactory
{
/// <summary>
/// Creates a new workflow builder.
/// </summary>
/// <returns>A new workflow builder.</returns>
IWorkflowBuilder CreateBuilder();
}

View file

@ -25,7 +25,7 @@ public class VariableConverter : JsonConverter<Variable>
}
/// <inheritdoc />
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<Variable>
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;

View file

@ -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<PolymorphicObjectConverterFactory>());
options.Converters.Add(GetService<TypeJsonConverter>());
options.Converters.Add(GetService<VariableConverterFactory>());
return options;
}

View file

@ -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<Variable> Variables);

View file

@ -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<IPayloadSerializer>();
}
[Fact(DisplayName = "Variable types remain intact after serialization")]
public void Test1()
{
// Create collection of variables to serialize.
var variables = new Collection<Variable>();
var model = new VariablesContainer(variables);
// Create a typed variable.
var variable = new Variable<bool>();
// Add variable to collection.
variables.Add(variable);
// Serialize collection.
var json = _payloadSerializer.Serialize(model);
// Deserialize collection.
var deserializedModel = _payloadSerializer.Deserialize<VariablesContainer>(json);
// Get the first variable.
var deserializedVariable = deserializedModel.Variables.First();
// Assert that the variable is of the correct type.
Assert.IsType<Variable<bool>>(deserializedVariable);
}
}

View file

@ -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<bool>();
}
}