diff --git a/src/modules/Elsa.Workflows.Core/Extensions/VariableExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/VariableExtensions.cs index 05e2ac287..125040e79 100644 --- a/src/modules/Elsa.Workflows.Core/Extensions/VariableExtensions.cs +++ b/src/modules/Elsa.Workflows.Core/Extensions/VariableExtensions.cs @@ -4,6 +4,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Text.Unicode; using Elsa.Expressions.Helpers; +using Elsa.Expressions.Models; using Elsa.Workflows; using Elsa.Workflows.Memory; using Elsa.Workflows.Serialization.Converters; @@ -62,6 +63,19 @@ public static class VariableExtensions variable.StorageDriverType = storageDriverType; return variable; } + + public static void Set(this Variable variable, ActivityExecutionContext context, object? value) + { + // Validate type compatibility. + if (!variable.TryParseValue(value, out var parsedValue)) + { + var variableType = variable.GetVariableType(); + throw new InvalidCastException($"The value '{value}' is not compatible with the variable '{variable.Name}' of type '{variableType.FullName}'."); + } + + // Set the value. + ((MemoryBlockReference)variable).Set(context, parsedValue); + } /// /// Converts the specified value into a type that is compatible with the variable. @@ -73,6 +87,24 @@ public static class VariableExtensions var converterOptions = new ObjectConverterOptions(SerializerOptions); return genericType == null ? value : value?.ConvertTo(genericType, converterOptions); } + + /// + /// Converts the specified value into a type that is compatible with the variable. + /// + [RequiresUnreferencedCode("Calls System.Text.Json.JsonSerializer.Serialize(TValue, JsonSerializerOptions)")] + public static bool TryParseValue(this Variable variable, object? value, out object? parsedValue) + { + try + { + parsedValue = variable.ParseValue(value); + return true; + } + catch + { + parsedValue = null; + return false; + } + } /// /// Return the type of the variable. diff --git a/src/modules/Elsa.Workflows.Core/Services/VariablePersistenceManager.cs b/src/modules/Elsa.Workflows.Core/Services/VariablePersistenceManager.cs index d4e17ce3f..663e0057d 100644 --- a/src/modules/Elsa.Workflows.Core/Services/VariablePersistenceManager.cs +++ b/src/modules/Elsa.Workflows.Core/Services/VariablePersistenceManager.cs @@ -1,17 +1,19 @@ using Elsa.Expressions.Models; using Elsa.Extensions; using Elsa.Workflows.Memory; +using Microsoft.Extensions.Logging; namespace Elsa.Workflows; /// -public class VariablePersistenceManager(IStorageDriverManager storageDriverManager) : IVariablePersistenceManager +public class VariablePersistenceManager(IStorageDriverManager storageDriverManager, ILogger logger) : IVariablePersistenceManager { /// - public async Task LoadVariablesAsync(WorkflowExecutionContext workflowExecutionContext, IEnumerable? excludeTags = default) + public async Task LoadVariablesAsync(WorkflowExecutionContext workflowExecutionContext, IEnumerable? excludeTags = null) { var cancellationToken = workflowExecutionContext.CancellationToken; var contexts = workflowExecutionContext.ActivityExecutionContexts.ToList(); + var excludeTagsList = excludeTags?.ToList(); foreach (var context in contexts) { @@ -34,15 +36,21 @@ public class VariablePersistenceManager(IStorageDriverManager storageDriverManag if (driver == null) continue; - if (excludeTags != null && driver.Tags.Any(excludeTags!.Contains)) + if (excludeTagsList != null && driver.Tags.Any(excludeTagsList.Contains)) continue; var id = GetStateId(variable); var value = await driver.ReadAsync(id, storageDriverContext); if (value == null) continue; - var parsedValue = variable.ParseValue(value); register.Declare(variable); + + if (!variable.TryParseValue(value, out var parsedValue)) + { + logger.LogWarning("Failed to parse value for variable {VariableId} of type {VariableType} with value {Value}", variable.Id, variable.GetVariableType().FullName, value); + continue; + } + variable.Set(register, parsedValue); } }