55using System . Linq . Dynamic . Core ;
66using System . Linq . Expressions ;
77using System . Reflection ;
8+ using System . Text . RegularExpressions ;
89using Newtonsoft . Json . Linq ;
910using WorkflowCore . Interface ;
1011using WorkflowCore . Models ;
@@ -18,6 +19,40 @@ public class DefinitionLoader : IDefinitionLoader
1819 {
1920 private readonly IWorkflowRegistry _registry ;
2021 private readonly ITypeResolver _typeResolver ;
22+
23+ // ParsingConfig to allow access to commonly used .NET methods like object.Equals
24+ private static readonly ParsingConfig ParsingConfig = new ParsingConfig
25+ {
26+ AllowNewToEvaluateAnyType = true ,
27+ AreContextKeywordsEnabled = true
28+ } ;
29+
30+ // Transform expressions to be compatible with System.Linq.Dynamic.Core 1.6.0+
31+ private static string TransformExpression ( string expression )
32+ {
33+ if ( string . IsNullOrEmpty ( expression ) )
34+ return expression ;
35+
36+ // Transform object.Equals(a, b) to Convert.ToBoolean(a) == Convert.ToBoolean(b)
37+ // This is a simple regex replacement for the common pattern
38+ var objectEqualsPattern = @"object\.Equals\s*\(\s*([^,]+)\s*,\s*([^)]+)\s*\)" ;
39+ var transformed = Regex . Replace ( expression , objectEqualsPattern ,
40+ match =>
41+ {
42+ var arg1 = match . Groups [ 1 ] . Value . Trim ( ) ;
43+ var arg2 = match . Groups [ 2 ] . Value . Trim ( ) ;
44+
45+ // If arg2 is a boolean literal, convert arg1 to boolean and compare
46+ if ( arg2 == "true" || arg2 == "false" )
47+ {
48+ return $ "Convert.ToBoolean({ arg1 } ) == { arg2 } ";
49+ }
50+ // Otherwise, convert both to strings for comparison
51+ return $ "Convert.ToString({ arg1 } ) == Convert.ToString({ arg2 } )";
52+ } ) ;
53+
54+ return transformed ;
55+ }
2156
2257 public DefinitionLoader ( IWorkflowRegistry registry , ITypeResolver typeResolver )
2358 {
@@ -94,7 +129,7 @@ private WorkflowStepCollection ConvertSteps(ICollection<StepSourceV1> source, Ty
94129 {
95130 var cancelExprType = typeof ( Expression < > ) . MakeGenericType ( typeof ( Func < , > ) . MakeGenericType ( dataType , typeof ( bool ) ) ) ;
96131 var dataParameter = Expression . Parameter ( dataType , "data" ) ;
97- var cancelExpr = DynamicExpressionParser . ParseLambda ( new [ ] { dataParameter } , typeof ( bool ) , nextStep . CancelCondition ) ;
132+ var cancelExpr = DynamicExpressionParser . ParseLambda ( ParsingConfig , false , new [ ] { dataParameter } , typeof ( bool ) , TransformExpression ( nextStep . CancelCondition ) ) ;
98133 targetStep . CancelCondition = cancelExpr ;
99134 }
100135
@@ -217,7 +252,7 @@ private void AttachOutputs(StepSourceV1 source, Type dataType, Type stepType, Wo
217252 foreach ( var output in source . Outputs )
218253 {
219254 var stepParameter = Expression . Parameter ( stepType , "step" ) ;
220- var sourceExpr = DynamicExpressionParser . ParseLambda ( new [ ] { stepParameter } , typeof ( object ) , output . Value ) ;
255+ var sourceExpr = DynamicExpressionParser . ParseLambda ( ParsingConfig , false , new [ ] { stepParameter } , typeof ( object ) , TransformExpression ( output . Value ) ) ;
221256
222257 var dataParameter = Expression . Parameter ( dataType , "data" ) ;
223258
@@ -344,7 +379,7 @@ private void AttachOutcomes(StepSourceV1 source, Type dataType, WorkflowStep ste
344379
345380 foreach ( var nextStep in source . SelectNextStep )
346381 {
347- var sourceDelegate = DynamicExpressionParser . ParseLambda ( new [ ] { dataParameter , outcomeParameter } , typeof ( object ) , nextStep . Value ) . Compile ( ) ;
382+ var sourceDelegate = DynamicExpressionParser . ParseLambda ( ParsingConfig , false , new [ ] { dataParameter , outcomeParameter } , typeof ( object ) , TransformExpression ( nextStep . Value ) ) . Compile ( ) ;
348383 Expression < Func < object , object , bool > > sourceExpr = ( data , outcome ) => System . Convert . ToBoolean ( sourceDelegate . DynamicInvoke ( data , outcome ) ) ;
349384 step . Outcomes . Add ( new ExpressionOutcome < object > ( sourceExpr )
350385 {
@@ -361,7 +396,7 @@ private Type FindType(string name)
361396 private static Action < IStepBody , object , IStepExecutionContext > BuildScalarInputAction ( KeyValuePair < string , object > input , ParameterExpression dataParameter , ParameterExpression contextParameter , ParameterExpression environmentVarsParameter , PropertyInfo stepProperty )
362397 {
363398 var expr = System . Convert . ToString ( input . Value ) ;
364- var sourceExpr = DynamicExpressionParser . ParseLambda ( new [ ] { dataParameter , contextParameter , environmentVarsParameter } , typeof ( object ) , expr ) ;
399+ var sourceExpr = DynamicExpressionParser . ParseLambda ( ParsingConfig , false , new [ ] { dataParameter , contextParameter , environmentVarsParameter } , typeof ( object ) , TransformExpression ( expr ) ) ;
365400
366401 void acn ( IStepBody pStep , object pData , IStepExecutionContext pContext )
367402 {
@@ -394,7 +429,7 @@ void acn(IStepBody pStep, object pData, IStepExecutionContext pContext)
394429 {
395430 if ( prop . Name . StartsWith ( "@" ) )
396431 {
397- var sourceExpr = DynamicExpressionParser . ParseLambda ( new [ ] { dataParameter , contextParameter , environmentVarsParameter } , typeof ( object ) , prop . Value . ToString ( ) ) ;
432+ var sourceExpr = DynamicExpressionParser . ParseLambda ( ParsingConfig , false , new [ ] { dataParameter , contextParameter , environmentVarsParameter } , typeof ( object ) , TransformExpression ( prop . Value . ToString ( ) ) ) ;
398433 object resolvedValue = sourceExpr . Compile ( ) . DynamicInvoke ( pData , pContext , Environment . GetEnvironmentVariables ( ) ) ;
399434 subobj . Remove ( prop . Name ) ;
400435 subobj . Add ( prop . Name . TrimStart ( '@' ) , JToken . FromObject ( resolvedValue ) ) ;
0 commit comments