microsoft / RulesEngine

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

Async method call with error: Methods are not accessible #507

Closed lichengxihuang closed 1 year ago

lichengxihuang commented 1 year ago

The following two rules give different behaviors:

  1. The non-static async call throws error: Exception while parsing expression myObject.GetCountAsync().Result < 3 - Methods on type 'MyObject' are not accessible
  2. The static async call was evaluated successfully.

From issue #226, it seems we do support async calls with non-static methods. However, from this code, it seems we don't? Did I miss anything?

public class MyObject
{
        public string Name { get; set; }

        public int Count { get; set; }

        public int GetCount()
        {
            return Count;
        }

        public async Task<int> GetCountAsync()
        {
            return await Task.FromResult(Count);
        }
}
public static class Utils
{
        public static async Task<int> GetCountAsync(MyObject data)
        {
            return await Task.FromResult(data.Count);
        }
}
public void Run()
{
    List<Workflow> workflows = new List<Workflow>();
    Workflow workflow = new Workflow();
    workflow.WorkflowName = "Test Workflow Rule";

    List<Rule> rules = new List<Rule>();

    Rule rule = new Rule {
        RuleName = "Test Rule",
        SuccessEvent = "Count is within tolerance.",
        ErrorMessage = "Not as expected.",
        Expression = "myObject.GetCountAsync().Result < 3",
        RuleExpressionType = RuleExpressionType.LambdaExpression
    };

    Rule rule2 = new Rule {
        RuleName = "Test Rule 2",
        SuccessEvent = "Count is within tolerance.",
        ErrorMessage = "Not as expected.",
        Expression = "Utils.GetCountAsync(myObject).Result < 3",
        RuleExpressionType = RuleExpressionType.LambdaExpression
    };

    rules.Add(rule);
    rules.Add(rule2);
    workflow.Rules = rules;
    workflows.Add(workflow);

    var reSettingsWithCustomTypes = new ReSettings { CustomTypes = new Type[] { typeof(Utils) } };
    var bre = new RulesEngine.RulesEngine(workflows.ToArray(), reSettingsWithCustomTypes);

    var myObject = new MyObject() {
        Name = "My Object",
        Count = 2
    };

    List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync(workflow.WorkflowName, new RuleParameter("myObject", myObject)).Result;
}
abbasc52 commented 1 year ago

Can you share the version of Rules Engine you are using?

lichengxihuang commented 1 year ago

Can you share the version of Rules Engine you are using?

The version I used was 4.0.0.

Thanks for the hint, when I bumped to the latest version 5.0.1, the issue was solved.

However, I got another issue: Exception while parsing expression Utils.GetCountAsync(myObject).Result < 3 - '.' or '(' or string literal expected It seems related to this:

List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync(workflow.WorkflowName, new RuleParameter("myObject", myObject)).Result;

When I change to another name, it worked.

List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync(workflow.WorkflowName, new RuleParameter("myObj", myObject)).Result;

Is myObject a reserved keyword?

abbasc52 commented 1 year ago

There is a bug in our dependency library, if the class name and passed parameter name is same(even if case is different), it takes the type instead of the passed parameter.

The current workaround is using different name from class name.

Meanwhile, i will raise the bug in correct repo to get it fixed.