Closed khPhoenix closed 1 year ago
Hi. Something similar happened to me and downgrading to version 4.0.0 works as expected. It seems something is broken from version 5.0.0.
@khPhoenix can you share if you are using typed object as input or dynamic object?
@abbasc52 using an anonymous type from a linq select:
Hi @khPhoenix ,
I am able to reproduce your issue and there seems to be some weird behavior related to double.Parse
.
If i replace double.Parse
with float.Parse
it works as expected.
If i keep global param as string and then used double.Parse
in expression that too works.
I will need to dig deeper on this, since it looks like a corner case scenario. But current workaround would be to work with float.Parse or parsing it in final expression
This is the code generated in this case scenario which looks valid to me:
((input1.Count >= ruleCount) AndAlso (input1.Where(Param_0 => (Param_0.Value >= threshold)).Count() >= ruleCount))
(Func<object[], bool>)((object[] args) =>
{
List<f__AnonymousType6<double, string>> input1;
double threshold;
int ruleCount;
input1 = ((List<f__AnonymousType6<double, string>>)args[0]);
threshold = ((double)args[1]);
ruleCount = ((int)args[2]);
return ((input1.Count >= ruleCount) && (Enumerable.Count<f__AnonymousType6<double, string>>(Enumerable.Where<f__AnonymousType6<double, string>>(
input1,
(Func<f__AnonymousType6<double, string>, bool>)((f__AnonymousType6<double, string> ) =>
(.Value >= threshold)))) >= ruleCount));
});
((input1.Count >= ruleCount) AndAlso input1.OrderByDescending(Param_0 => Param_0.ChangeDateTime).Take(ruleCount).All(Param_1 => (Param_1.Value < threshold)))
(Func<object[], bool>)((object[] args) =>
{
List<f__AnonymousType6<double, string>> input1;
double threshold;
int ruleCount;
input1 = ((List<f__AnonymousType6<double, string>>)args[0]);
threshold = ((double)args[1]);
ruleCount = ((int)args[2]);
return ((input1.Count >= ruleCount) && Enumerable.All<f__AnonymousType6<double, string>>(
Enumerable.Take<f__AnonymousType6<double, string>>(
Enumerable.OrderByDescending<f__AnonymousType6<double, string>, string>(
input1,
(Func<f__AnonymousType6<double, string>, string>)((f__AnonymousType6<double, string> ) =>
.ChangeDateTime)),
ruleCount),
(Func<f__AnonymousType6<double, string>, bool>)((f__AnonymousType6<double, string> ) =>
(.Value < threshold))));
});
Hi @khPhoenix ,
I am able to reproduce your issue and there seems to be some weird behavior related to
double.Parse
. If i replacedouble.Parse
withfloat.Parse
it works as expected. If i keep global param as string and then useddouble.Parse
in expression that too works.I will need to dig deeper on this, since it looks like a corner case scenario. But current workaround would be to work with float.Parse or parsing it in final expression
This is the code generated in this case scenario which looks valid to me:
((input1.Count >= ruleCount) AndAlso (input1.Where(Param_0 => (Param_0.Value >= threshold)).Count() >= ruleCount)) (Func<object[], bool>)((object[] args) => { List<f__AnonymousType6<double, string>> input1; double threshold; int ruleCount; input1 = ((List<f__AnonymousType6<double, string>>)args[0]); threshold = ((double)args[1]); ruleCount = ((int)args[2]); return ((input1.Count >= ruleCount) && (Enumerable.Count<f__AnonymousType6<double, string>>(Enumerable.Where<f__AnonymousType6<double, string>>( input1, (Func<f__AnonymousType6<double, string>, bool>)((f__AnonymousType6<double, string> ) => (.Value >= threshold)))) >= ruleCount)); });
((input1.Count >= ruleCount) AndAlso input1.OrderByDescending(Param_0 => Param_0.ChangeDateTime).Take(ruleCount).All(Param_1 => (Param_1.Value < threshold))) (Func<object[], bool>)((object[] args) => { List<f__AnonymousType6<double, string>> input1; double threshold; int ruleCount; input1 = ((List<f__AnonymousType6<double, string>>)args[0]); threshold = ((double)args[1]); ruleCount = ((int)args[2]); return ((input1.Count >= ruleCount) && Enumerable.All<f__AnonymousType6<double, string>>( Enumerable.Take<f__AnonymousType6<double, string>>( Enumerable.OrderByDescending<f__AnonymousType6<double, string>, string>( input1, (Func<f__AnonymousType6<double, string>, string>)((f__AnonymousType6<double, string> ) => .ChangeDateTime)), ruleCount), (Func<f__AnonymousType6<double, string>, bool>)((f__AnonymousType6<double, string> ) => (.Value < threshold)))); });
Thanks for the update! I'll use one of the work arounds you listed for now :-)
Interesting the issue isn't presenting with the following workflow:
var workflow = new AlertWorkflow
{
WorkflowName = "MyWorkflow",
GlobalParams = new List<ScopedParam>
{
new ScopedParam
{
Name = "threshold",
Expression = "double.Parse(\"0.85\")"
}
},
Rules = new List<Rule>
{
new Rule
{
RuleName = AlertWorkflow.ActivationRule,
Enabled = true,
RuleExpressionType = RuleExpressionType.LambdaExpression,
Expression = "input1 > threshold"
},
new Rule
{
RuleName = AlertWorkflow.DeactivationRule,
Enabled = true,
RuleExpressionType = RuleExpressionType.LambdaExpression,
Expression = "threshold > input1"
}
}
};
@khPhoenix looks like a bug with latest version of FastExpressionCompiler. I have released v5.0.2 which fixes this.
I recently came across an issue while implementing RulesEngine in a .Net 7 project. I was able to setup my rules and they were running correctly when running on my Windows Development machine, but when deployed in a Linux docker container, they were not acting as expected.
Environment Details: Running in WSL:
Running in Docker/EC2
For the provided Rule below, in windows the Activation Rule
isSuccess
evaluates tofalse
as expected, Deactivation RuleisSuccess
evaluates totrue
.When running in Linux, as shown below, the results are the opposite of expected.
We were able to find a work around by removing the Global Param and hard coding it into the rule. After doing that the rule evaluated correctly.
Rule Json:
Evaluation result from Linux