microsoft / RulesEngine

A Json based Rules Engine with extensive Dynamic expression support
https://microsoft.github.io/RulesEngine/
MIT License
3.47k stars 528 forks source link

Custom method is not being called with ExecuteActionWorkflowAsync; throwing parser error. #584

Open lparee opened 4 months ago

lparee commented 4 months ago

Hi Team,

I am trying to execute my workflow using ExecuteActionWorkflowAsync method of MS rule engine but here I am not being able to use custom method in an expression, it is throwing parser error while execution.

Whereas it is working fine with ExecuteAllRulesAsync method.

I need to execute my rules in a sequence within a workflow with some custom methods in execution, hence, I have to use ExecuteActionWorkflowAsync method.

Here is a sample code.

//JSON: [ { "WorkflowName": "MyWorkFlow", "Rules": [ { "RuleName": "Rule1", "SuccessEvent": "ok", "ErrorMessage": "Reject", "ErrorType": "Error", "RuleExpressionType": "LambdaExpression", "Expression": "customMethods.doSomething()", "Actions": { //action } } } ]

// Custom method class public class CustomMethods {

public CustomMethods()
{

}

public bool doSomething()
{        
    return false;
}

}

//input construction var input1 = new RuleParameter("string1", "hello"); var cust = new RuleParameter("customMethods", customMethods);

//engine execution with action workflow _engine.ExecuteActionWorkflowAsync("MyWorkFlow","Rule1", {input1,cust }).Result;

//throwing parsing error "doSomething" is not accessible.

//engine execution with all rules _engine.ExecuteAllRulesAsync("MyWorkFlow",{input1,cust }).Result //working fine.

Regards Lokesh

RenanCarlosPereira commented 4 months ago

Hello @lparee,

It appears that the ExecuteActionWorkflowAsync method does not invoke the RegisterRule method. This is critical because RegisterRule is responsible for both registering the rule and auto-registering the input class when AutoRegisterInputType is enabled.

As a result, when using ExecuteActionWorkflowAsync, the inputs are not automatically imported, unlike the behavior observed with ExecuteAllRulesAsync, which does call RegisterRule. here

To mitigate this issue temporarily, you can manually register the class as demonstrated in the example below:

using RulesEngine.Models;
using System.Text.Json;

var rulesEngine = new RulesEngine.RulesEngine(new ReSettings { CustomTypes = new[] { typeof(User) } });

rulesEngine.AddWorkflow(new Workflow
{
    WorkflowName = "UserNameWorkFlow",
    Rules = new List<Rule>
    {
        new Rule
        {
            RuleName = "CheckFullName",
            Expression = @"user.FullName() == ""Renan Pereira"""
        }
    }
});

var parameter = RuleParameter.Create("user", new User { FirstName = "Renan", LastName = "Pereira" });

// This works without setting the CustomTypes.
var result1 = await rulesEngine.ExecuteAllRulesAsync("UserNameWorkFlow", parameter);
Console.WriteLine(JsonSerializer.SerializeToElement(result1, new JsonSerializerOptions { WriteIndented = true }));

// This does not work without setting the CustomTypes.
var result2 = await rulesEngine.ExecuteActionWorkflowAsync("UserNameWorkFlow", "CheckFullName", new[] { parameter });
Console.WriteLine(JsonSerializer.SerializeToElement(result2, new JsonSerializerOptions { WriteIndented = true }));

Console.ReadLine();

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public string FullName() => $"{FirstName} {LastName}";
}

This workaround involves setting CustomTypes explicitly until a permanent fix is implemented via a Pull Request.

asulwer commented 1 week ago

i tested and it works fine. i wrote a demp app supporting this in my fork