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

Subject: Query Regarding RulesEngine: Execution error - "Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpression1' t.o type 'System.Linq.Expressions.ParameterExpression" #499

Open Amina-2310 opened 1 year ago

Amina-2310 commented 1 year ago

Hello,

I am writing to seek assistance regarding an issue we are encountering while using the RulesEngine. We have a RulesExpression with multiple rules, where the output of one rule is used as input for another rule. However, we are experiencing an error during the execution of the second rule's expression.

Here are the details of our RulesExpression:

{
  "RuleExpression": [
    {
      "WorkflowName": "DataBuilder",
      "Rules": [
        {
          "RuleName": "GetAuthorDetails",
          "Expression": "input1.ApiOutputs.FirstOrDefault(x => x.ExternalApiIdentifier == \"NessieSearchPeopleApi\") != null",
          "Actions": {
            "OnSuccess": {
              "Name": "OutputExpression",
              "Context": {
                "Expression": "input1.ApiOutputs.FirstOrDefault(x => x.ExternalApiIdentifier == \"NessieSearchPeopleApi\").Input.people"
              }
            }
          }
        }
      ]
    },
    {
      "WorkflowName": "DataBuilder",
      "Rules": [
        {
          "RuleName": "GetAuthorDetails",
          "Expression": "input2 != null",
          "Actions": {
            "OnSuccess": {
              "Name": "OutputExpression",
              "Context": {
                "Expression": "input2.FirstOrDefault(x => x.fullName != null);"
              }
            }
          }
        }
      ]
    }
  ]
}

We have a C# code snippet that parses and executes the rules:

var newInput = new Object();
var workflows = JsonConvert.DeserializeObject<List<Workflow>>(payload.RuleExpression.ToString());
foreach (var workflow in workflows)
{
    var workflowList = new List<Workflow>();
    workflowList.Add(workflow);
    var bre = new RulesEngine.RulesEngine(workflowList.ToArray(), null);
    List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("DataBuilder", resolverInput, newInput).Result;
    var resultFromRule = resultList[0].ActionResult.Output;
    newInput = resultFromRule;       
}

During the execution of the second rule's expression, we are encountering the following error: 'Exception while executing OutputExpressionAction: Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpression1' to type 'System.Linq.Expressions.ParameterExpression'.'

The error occurs specifically in the expression: "Expression": "input2.FirstOrDefault(x => x.fullName != null);"

We would greatly appreciate any insights, suggestions, or guidance on how to resolve this error and successfully execute the second rule's expression.

Thank you in advance for your assistance. Best regards, Amina

pramireddy commented 1 year ago

Hello,

Attached Rules Schema and Code Snippet are not clear:

I hope it's helps to resolve your issue.

Cheerio Prasad RAMIREDDY

Amina-2310 commented 1 year ago

Hi

Sorry for the confusion

Here are the Rules Schema and inputs used for executing the expressions

1 - Rules Schema

[
    {
        "WorkflowName": "DataBuilder",
        "Rules": [
            {
                "RuleName": "GetAuthorDetails",
                "Expression": "input1.ApiOutputs.FirstOrDefault(x => x.ExternalApiIdentifier == \"NessieSearchPeopleApi\") != null",
                "Actions": {
                    "OnSuccess": {
                        "Name": "OutputExpression",
                        "Context": {
                            "Expression": "input1.ApiOutputs.FirstOrDefault(x => x.ExternalApiIdentifier == \"NessieSearchPeopleApi\").Input.people"
                        }
                    }
                }
            }
        ]
    },
    {
        "WorkflowName": "DataBuilder",
        "Rules": [
            {
                "RuleName": "GetAuthorDetails",
                "Expression": "input2 != null",
                "Actions": {
                    "OnSuccess": {
                        "Name": "OutputExpression",
                        "Context": {
                            "Expression": "input2.FirstOrDefault(x => x.fullName != null);"
                        }
                    }
                }
            }
        ]
    }
]

2 - input1.ApiOutputs used in the first expression
_"Expression": "input1.ApiOutputs.FirstOrDefault(x => x.ExternalApiIdentifier == \"NessieSearchPeopleApi\").Input.people",_

[
    {
        "ExternalApiIdentifier": "NessieSearchPeopleApi",
        "JobUId": "e18ab695-9bf0-4b64-8bf4-36cf67d5f1e6",
        "Input": {
            "people": [
                {
                    "queryId": "27179be6-1db9-4e4f-8fc6-c309825a43d5",
                    "emails": [
                        "genetics.editorial.office@frontiersin.org.test"
                    ],
                    "fullName": "FrontiersinGenetics",
                    "affiliations": [
                        {
                            "id": 241183997,
                            "name": "FrontiersMediaSA",
                            "countryName": "Switzerland"
                        }
                    ]
                },
                {
                    "queryId": "27179be6-1db9-4e4f-8fc6-c309825a43d5",
                    "emails": [
                        "genetics.editorial.office@frontiersin.org.test"
                    ],
                    "fullName": null,
                    "affiliations": [
                        {
                            "id": 241183997,
                            "name": "FrontiersMediaSA",
                            "countryName": "Switzerland"
                        }
                    ]
                }
            ],
            "filters": {
                "exclusionCategories": []
            },
            "results": {
                "unknownThreshold": 1,
                "maxResults": 1
            },
            "applicationName": "JournalAIRAQualityCheck"
        },
        "Processed": true,
        "Message": null,
        "ResponseContent": []
    }
]

3 - input2 We are using the output of this first expression as input2 of the second expression and it is defined as an object that is strored in the newInput of the code

{[input2, {[
  {
    "queryId": "27179be6-1db9-4e4f-8fc6-c309825a43d5",
    "emails": [
      "genetics.editorial.office@frontiersin.org.test"
    ],
    "fullName": "FrontiersinGenetics",
    "affiliations": [
      {
        "id": 241183997,
        "name": "FrontiersMediaSA",
        "countryName": "Switzerland"
      }
    ]
  },
  {
    "queryId": "27179be6-1db9-4e4f-8fc6-c309825a43d5",
    "emails": [
      "genetics.editorial.office@frontiersin.org.test"
    ],
    "fullName": null,
    "affiliations": [
      {
        "id": 241183997,
        "name": "FrontiersMediaSA",
        "countryName": "Switzerland"
      }
    ]
  }
]}]}

Here is the expression we are getting the error

input2.FirstOrDefault(x => x.fullName != null)

abbasc52 commented 1 year ago

@Amina-2310 not sure if it is a typo but can you try after removing the trailing semicolon here: input2.FirstOrDefault(x => x.fullName != null);

Amina-2310 commented 1 year ago

Hi I have tried with removing semicolon. But still same issue is there.

pramireddy commented 1 year ago

It's working for me after typo correction. @Amina-2310 May be Visual Studio cache issue. Clean the solution and run again.

I tested with: [ { "WorkflowName": "DataBuilder", "Rules": [ { "RuleName": "GetAuthorDetails", "Expression": "input1.ApiOutputs.FirstOrDefault(x => x.ExternalApiIdentifier == \"NessieSearchPeopleApi\") != null", "Actions": { "OnSuccess": { "Name": "OutputExpression", "Context": { "Expression": "input1.ApiOutputs.FirstOrDefault(x => x.ExternalApiIdentifier == \"NessieSearchPeopleApi\").Input.people" } } } } ] }, { "WorkflowName": "DataBuilder", "Rules": [ { "RuleName": "GetAuthorDetails", "Expression": "input2 != null", "Actions": { "OnSuccess": { "Name": "OutputExpression", "Context": { "Expression": "input2.FirstOrDefault(x => x.fullName != null)" } } } } ] } ]

With Test Data: Input 1: [ { "WorkflowName": "DataBuilder", "Rules": [ { "RuleName": "GetAuthorDetails", "Expression": "input1.ApiOutputs.FirstOrDefault(x => x.ExternalApiIdentifier == \"NessieSearchPeopleApi\") != null", "Actions": { "OnSuccess": { "Name": "OutputExpression", "Context": { "Expression": "input1.ApiOutputs.FirstOrDefault(x => x.ExternalApiIdentifier == \"NessieSearchPeopleApi\").Input.people" } } } } ] }, { "WorkflowName": "DataBuilder", "Rules": [ { "RuleName": "GetAuthorDetails", "Expression": "input2 != null", "Actions": { "OnSuccess": { "Name": "OutputExpression", "Context": { "Expression": "input2.FirstOrDefault(x => x.fullName != null)" } } } } ] } ]

Input 2: [ { "queryId": "27179be6-1db9-4e4f-8fc6-c309825a43d5", "emails": [ "genetics.editorial.office@frontiersin.org.test" ], "fullName": "FrontiersinGenetics", "affiliations": [ { "id": 241183997, "name": "FrontiersMediaSA", "countryName": "Switzerland" } ] }, { "queryId": "27179be6-1db9-4e4f-8fc6-c309825a43d5", "emails": [ "genetics.editorial.office@frontiersin.org.test" ], "fullName": null, "affiliations": [ { "id": 241183997, "name": "FrontiersMediaSA", "countryName": "Switzerland" } ] } ]

Amina-2310 commented 1 year ago

Hi

Could you please confirm that input2 is stored as an object rather than a model.


var newInput = new Object();
var workflows = JsonConvert.DeserializeObject<List<Workflow>>(payload.RuleExpression.ToString());
foreach (var workflow in workflows)
{
    var workflowList = new List<Workflow>();
    workflowList.Add(workflow);
    var bre = new RulesEngine.RulesEngine(workflowList.ToArray(), null);
    List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("DataBuilder", resolverInput, newInput).Result;
    var resultFromRule = resultList[0].ActionResult.Output;
    newInput = resultFromRule;       
}

this is the code for executing the expression . Here input2 is the result of first expression and is treated as an object
premsoft commented 11 months ago

Hi @pramireddy, May I know if you had an opportunity to review the last point made by Amina?

abbasc52 commented 10 months ago

@Amina-2310. Could you try using dynamic newInput = new Object(); RulesEngine requires Inputs of either strong type or ExpandoObject