From 170b494b66d4102a006d6b45992057d639d4eb1e Mon Sep 17 00:00:00 2001 From: Abbas Cyclewala Date: Mon, 20 Jul 2020 20:04:18 +0530 Subject: [PATCH] Fixed dynamic object support when using RuleParameter (#33) --- demo/DemoApp/BasicDemo.cs | 60 ++++++++++++++++++++++ demo/DemoApp/NestedInputDemo.cs | 8 +-- demo/DemoApp/Program.cs | 55 ++------------------ .../RulesEngine/Models/RuleParameter.cs | 23 +++------ src/RulesEngine/RulesEngine/RulesEngine.cs | 3 +- src/RulesEngine/RulesEngine/RulesEngine.csproj | 2 +- test/RulesEngine.UnitTest/UtilsTests.cs | 18 +++++++ 7 files changed, 93 insertions(+), 76 deletions(-) create mode 100644 demo/DemoApp/BasicDemo.cs diff --git a/demo/DemoApp/BasicDemo.cs b/demo/DemoApp/BasicDemo.cs new file mode 100644 index 0000000..9812b7e --- /dev/null +++ b/demo/DemoApp/BasicDemo.cs @@ -0,0 +1,60 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using RulesEngine.Models; +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.IO; +using static RulesEngine.Extensions.ListofRuleResultTreeExtension; + +namespace DemoApp +{ + public class BasicDemo + { + public void Run() + { + Console.WriteLine($"Running {nameof(BasicDemo)}...."); + var basicInfo = "{\"name\": \"hello\",\"email\": \"abcy@xyz.com\",\"creditHistory\": \"good\",\"country\": \"canada\",\"loyalityFactor\": 3,\"totalPurchasesToDate\": 10000}"; + var orderInfo = "{\"totalOrders\": 5,\"recurringItems\": 2}"; + var telemetryInfo = "{\"noOfVisitsPerMonth\": 10,\"percentageOfBuyingToVisit\": 15}"; + + var converter = new ExpandoObjectConverter(); + + dynamic input1 = JsonConvert.DeserializeObject(basicInfo, converter); + dynamic input2 = JsonConvert.DeserializeObject(orderInfo, converter); + dynamic input3 = JsonConvert.DeserializeObject(telemetryInfo, converter); + + var inputs = new dynamic[] + { + input1, + input2, + input3 + }; + + var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "Discount.json", SearchOption.AllDirectories); + if (files == null || files.Length == 0) + throw new Exception("Rules not found."); + + var fileData = File.ReadAllText(files[0]); + var workflowRules = JsonConvert.DeserializeObject>(fileData); + + var bre = new RulesEngine.RulesEngine(workflowRules.ToArray(), null); + + string discountOffered = "No discount offered."; + + List resultList = bre.ExecuteRule("Discount", inputs); + + resultList.OnSuccess((eventName) => + { + discountOffered = $"Discount offered is {eventName} % over MRP."; + }); + + resultList.OnFail(() => + { + discountOffered = "The user is not eligible for any discount."; + }); + + Console.WriteLine(discountOffered); + } + } +} diff --git a/demo/DemoApp/NestedInputDemo.cs b/demo/DemoApp/NestedInputDemo.cs index bd69ec7..95c6bca 100644 --- a/demo/DemoApp/NestedInputDemo.cs +++ b/demo/DemoApp/NestedInputDemo.cs @@ -13,10 +13,11 @@ namespace DemoApp public string Value { get; set; } } - class NestedInputDemo + public class NestedInputDemo { - public static void Main(string[] args) + public void Run() { + Console.WriteLine($"Running {nameof(NestedInputDemo)}...."); var nestedInput = new { SimpleProp = "simpleProp", NestedProp = new @@ -57,8 +58,7 @@ namespace DemoApp }).OnFail(() => { Console.WriteLine($"{workflow.WorkflowName} evaluation resulted in failure"); - }) - ; + }); } diff --git a/demo/DemoApp/Program.cs b/demo/DemoApp/Program.cs index 687e22a..e32873b 100644 --- a/demo/DemoApp/Program.cs +++ b/demo/DemoApp/Program.cs @@ -1,63 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using RulesEngine.Models; -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.IO; -using static RulesEngine.Extensions.ListofRuleResultTreeExtension; - namespace DemoApp { - class Program + static class Program { static void Main(string[] args) { - var basicInfo = "{\"name\": \"Dishant\",\"email\": \"dishantmunjal@live.com\",\"creditHistory\": \"good\",\"country\": \"canada\",\"loyalityFactor\": 3,\"totalPurchasesToDate\": 10000}"; - var orderInfo = "{\"totalOrders\": 5,\"recurringItems\": 2}"; - var telemetryInfo = "{\"noOfVisitsPerMonth\": 10,\"percentageOfBuyingToVisit\": 15}"; - - var converter = new ExpandoObjectConverter(); - - dynamic input1 = JsonConvert.DeserializeObject(basicInfo, converter); - dynamic input2 = JsonConvert.DeserializeObject(orderInfo, converter); - dynamic input3 = JsonConvert.DeserializeObject(telemetryInfo, converter); - - var inputs = new dynamic[] - { - input1, - input2, - input3 - }; - - var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "Discount.json", SearchOption.AllDirectories); - if (files == null || files.Length == 0) - throw new Exception("Rules not found."); - - var fileData = File.ReadAllText(files[0]); - var workflowRules = JsonConvert.DeserializeObject>(fileData); - - var bre = new RulesEngine.RulesEngine(workflowRules.ToArray(), null); - - string discountOffered = "No discount offered."; - - List resultList = bre.ExecuteRule("Discount", inputs); - - resultList.OnSuccess((eventName) => - { - discountOffered = $"Discount offered is {eventName} % over MRP."; - }); - - resultList.OnFail(() => - { - discountOffered = "The user is not eligible for any discount."; - }); - - Console.WriteLine(discountOffered); - + new BasicDemo().Run(); + new NestedInputDemo().Run(); } } } diff --git a/src/RulesEngine/RulesEngine/Models/RuleParameter.cs b/src/RulesEngine/RulesEngine/Models/RuleParameter.cs index 400943a..639a26f 100644 --- a/src/RulesEngine/RulesEngine/Models/RuleParameter.cs +++ b/src/RulesEngine/RulesEngine/Models/RuleParameter.cs @@ -3,34 +3,23 @@ using System; using System.Diagnostics.CodeAnalysis; +using RulesEngine.HelperFunctions; namespace RulesEngine.Models { [ExcludeFromCodeCoverage] public class RuleParameter { - public RuleParameter(Type type) - { - Type = type; - Name = type.Name; - } - public RuleParameter(Type type,string name) - { - Type = type; - Name = name; - } - public RuleParameter(string name,object value) { - Type = value.GetType(); + Value = Utils.GetTypedObject(value); + Type = Value.GetType(); Name = name; - Value = value; } - - public Type Type { get; set; } - public string Name { get; set; } - public object Value { get; set; } + public Type Type { get; } + public string Name { get; } + public object Value { get; } } } diff --git a/src/RulesEngine/RulesEngine/RulesEngine.cs b/src/RulesEngine/RulesEngine/RulesEngine.cs index 3bc943f..1422086 100644 --- a/src/RulesEngine/RulesEngine/RulesEngine.cs +++ b/src/RulesEngine/RulesEngine/RulesEngine.cs @@ -60,8 +60,7 @@ namespace RulesEngine for (int i = 0; i < inputs.Length; i++) { var input = inputs[i]; - var obj = Utils.GetTypedObject(input); - ruleParams.Add(new RuleParameter($"input{i + 1}", obj)); + ruleParams.Add(new RuleParameter($"input{i + 1}", input)); } return ExecuteRule(workflowName, ruleParams.ToArray()); diff --git a/src/RulesEngine/RulesEngine/RulesEngine.csproj b/src/RulesEngine/RulesEngine/RulesEngine.csproj index 09b613a..4a367e2 100644 --- a/src/RulesEngine/RulesEngine/RulesEngine.csproj +++ b/src/RulesEngine/RulesEngine/RulesEngine.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 2.0.0 + 2.0.1 Copyright (c) Microsoft Corporation. LICENSE https://github.com/microsoft/RulesEngine diff --git a/test/RulesEngine.UnitTest/UtilsTests.cs b/test/RulesEngine.UnitTest/UtilsTests.cs index 58a73e9..b0d3625 100644 --- a/test/RulesEngine.UnitTest/UtilsTests.cs +++ b/test/RulesEngine.UnitTest/UtilsTests.cs @@ -31,6 +31,24 @@ namespace RulesEngine.UnitTest Assert.NotNull(typedobj.GetType().GetProperty("test")); } + [Fact] + public void GetTypedObject_dynamicObject_multipleObjects() + { + dynamic obj = new ExpandoObject(); + obj.test = "hello"; + obj.testList = new List { 1, 2, 3 }; + dynamic obj2 = new ExpandoObject(); + obj2.test = "world"; + obj2.testList = new List { 1, 2, 3 }; + object typedobj = Utils.GetTypedObject(obj); + object typedobj2 = Utils.GetTypedObject(obj2); + Assert.IsNotType(typedobj); + Assert.NotNull(typedobj.GetType().GetProperty("test")); + Console.WriteLine($"{typedobj.GetType()} & {typedobj2.GetType()}"); + Assert.Equal(typedobj.GetType(),typedobj2.GetType()); + } + + [Fact] public void GetTypedObject_nonDynamicObject() {