diff --git a/src/WorkflowCore.DSL/Services/DefinitionLoader.cs b/src/WorkflowCore.DSL/Services/DefinitionLoader.cs index c5cc5e083..aa22988eb 100644 --- a/src/WorkflowCore.DSL/Services/DefinitionLoader.cs +++ b/src/WorkflowCore.DSL/Services/DefinitionLoader.cs @@ -5,6 +5,7 @@ using System.Linq.Dynamic.Core; using System.Linq.Expressions; using System.Reflection; +using System.Text.RegularExpressions; using Newtonsoft.Json.Linq; using WorkflowCore.Interface; using WorkflowCore.Models; @@ -18,6 +19,40 @@ public class DefinitionLoader : IDefinitionLoader { private readonly IWorkflowRegistry _registry; private readonly ITypeResolver _typeResolver; + + // ParsingConfig to allow access to commonly used .NET methods like object.Equals + private static readonly ParsingConfig ParsingConfig = new ParsingConfig + { + AllowNewToEvaluateAnyType = true, + AreContextKeywordsEnabled = true + }; + + // Transform expressions to be compatible with System.Linq.Dynamic.Core 1.6.0+ + private static string TransformExpression(string expression) + { + if (string.IsNullOrEmpty(expression)) + return expression; + + // Transform object.Equals(a, b) to Convert.ToBoolean(a) == Convert.ToBoolean(b) + // This is a simple regex replacement for the common pattern + var objectEqualsPattern = @"object\.Equals\s*\(\s*([^,]+)\s*,\s*([^)]+)\s*\)"; + var transformed = Regex.Replace(expression, objectEqualsPattern, + match => + { + var arg1 = match.Groups[1].Value.Trim(); + var arg2 = match.Groups[2].Value.Trim(); + + // If arg2 is a boolean literal, convert arg1 to boolean and compare + if (arg2 == "true" || arg2 == "false") + { + return $"Convert.ToBoolean({arg1}) == {arg2}"; + } + // Otherwise, convert both to strings for comparison + return $"Convert.ToString({arg1}) == Convert.ToString({arg2})"; + }); + + return transformed; + } public DefinitionLoader(IWorkflowRegistry registry, ITypeResolver typeResolver) { @@ -94,7 +129,7 @@ private WorkflowStepCollection ConvertSteps(ICollection source, Ty { var cancelExprType = typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(dataType, typeof(bool))); var dataParameter = Expression.Parameter(dataType, "data"); - var cancelExpr = DynamicExpressionParser.ParseLambda(new[] { dataParameter }, typeof(bool), nextStep.CancelCondition); + var cancelExpr = DynamicExpressionParser.ParseLambda(ParsingConfig, false, new[] { dataParameter }, typeof(bool), TransformExpression(nextStep.CancelCondition)); targetStep.CancelCondition = cancelExpr; } @@ -217,7 +252,7 @@ private void AttachOutputs(StepSourceV1 source, Type dataType, Type stepType, Wo foreach (var output in source.Outputs) { var stepParameter = Expression.Parameter(stepType, "step"); - var sourceExpr = DynamicExpressionParser.ParseLambda(new[] { stepParameter }, typeof(object), output.Value); + var sourceExpr = DynamicExpressionParser.ParseLambda(ParsingConfig, false, new[] { stepParameter }, typeof(object), TransformExpression(output.Value)); var dataParameter = Expression.Parameter(dataType, "data"); @@ -344,7 +379,7 @@ private void AttachOutcomes(StepSourceV1 source, Type dataType, WorkflowStep ste foreach (var nextStep in source.SelectNextStep) { - var sourceDelegate = DynamicExpressionParser.ParseLambda(new[] { dataParameter, outcomeParameter }, typeof(object), nextStep.Value).Compile(); + var sourceDelegate = DynamicExpressionParser.ParseLambda(ParsingConfig, false, new[] { dataParameter, outcomeParameter }, typeof(object), TransformExpression(nextStep.Value)).Compile(); Expression> sourceExpr = (data, outcome) => System.Convert.ToBoolean(sourceDelegate.DynamicInvoke(data, outcome)); step.Outcomes.Add(new ExpressionOutcome(sourceExpr) { @@ -361,7 +396,7 @@ private Type FindType(string name) private static Action BuildScalarInputAction(KeyValuePair input, ParameterExpression dataParameter, ParameterExpression contextParameter, ParameterExpression environmentVarsParameter, PropertyInfo stepProperty) { var expr = System.Convert.ToString(input.Value); - var sourceExpr = DynamicExpressionParser.ParseLambda(new[] { dataParameter, contextParameter, environmentVarsParameter }, typeof(object), expr); + var sourceExpr = DynamicExpressionParser.ParseLambda(ParsingConfig, false, new[] { dataParameter, contextParameter, environmentVarsParameter }, typeof(object), TransformExpression(expr)); void acn(IStepBody pStep, object pData, IStepExecutionContext pContext) { @@ -394,7 +429,7 @@ void acn(IStepBody pStep, object pData, IStepExecutionContext pContext) { if (prop.Name.StartsWith("@")) { - var sourceExpr = DynamicExpressionParser.ParseLambda(new[] { dataParameter, contextParameter, environmentVarsParameter }, typeof(object), prop.Value.ToString()); + var sourceExpr = DynamicExpressionParser.ParseLambda(ParsingConfig, false, new[] { dataParameter, contextParameter, environmentVarsParameter }, typeof(object), TransformExpression(prop.Value.ToString())); object resolvedValue = sourceExpr.Compile().DynamicInvoke(pData, pContext, Environment.GetEnvironmentVariables()); subobj.Remove(prop.Name); subobj.Add(prop.Name.TrimStart('@'), JToken.FromObject(resolvedValue)); diff --git a/src/WorkflowCore.DSL/WorkflowCore.DSL.csproj b/src/WorkflowCore.DSL/WorkflowCore.DSL.csproj index 94765a53e..9385da3d0 100644 --- a/src/WorkflowCore.DSL/WorkflowCore.DSL.csproj +++ b/src/WorkflowCore.DSL/WorkflowCore.DSL.csproj @@ -11,7 +11,7 @@ - +