做企业网站用什么软件,石家庄市规划建设局网站,滨州的网站开发,南京品牌网站建设当编写应用程序时#xff0c;经常性需要花费大量的时间与精力处理业务逻辑#xff0c;往往业务逻辑的变化需要重构或者增加大量代码#xff0c;对开发测试人员很不友好。之前在这篇文章说过#xff0c;可以使用脚本引擎来将我们需要经常变化的代码进行动态编译执行#xf… 当编写应用程序时经常性需要花费大量的时间与精力处理业务逻辑往往业务逻辑的变化需要重构或者增加大量代码对开发测试人员很不友好。之前在这篇文章说过可以使用脚本引擎来将我们需要经常变化的代码进行动态编译执行自由度非常大不过对应的需要资源也多。如果只是针对非常具体业务逻辑的变化可以尝试使用RulesEngine对程序进行操作。下文使用了官方示例且部分内容翻译自说明文档简介RulesEngine是微软推出的规则引擎规则引擎在很多企业开发中有所应用是处理经常变动需求的一种优雅的方法。个人任务规则引擎适用于以下的一些场景输入输出类型数量比较固定但是执行逻辑经常变化switch条件经常变化复杂switch语句的替代会变动的具有多种条件或者规则的业务逻辑规则自由度不要求特别高的场景。这种情况建议使用脚本引擎RulesEngine的规则使用JSON进行存储通过lambda表达式方式表述规则Rules。安装很方便直接使用nuget进行安装Copyinstall-pacakge RulesEngine
规则定义需要有Rules有WorkflowName然后还有一些属性。Copy[{WorkflowName: Discount,Rules: [{RuleName: GiveDiscount10,SuccessEvent: 10,ErrorMessage: One or more adjust rules failed.,ErrorType: Error,RuleExpressionType: LambdaExpression,Expression: input1.country \india\ AND input1.loyalityFactor 2 AND input1.totalPurchasesToDate 5000 AND input2.totalOrders 2 AND input3.noOfVisitsPerMonth 2}]}
]
除了标准的RuleExpressionType还可以通过定义Rules嵌套多个条件下面是Or逻辑。Copy{
RuleName: GiveDiscount30NestedOrExample,
SuccessEvent: 30,
ErrorMessage: One or more adjust rules failed.,
ErrorType: Error,
Operator: OrElse,
Rules:[{RuleName: IsLoyalAndHasGoodSpend,ErrorMessage: One or more adjust rules failed.,ErrorType: Error,RuleExpressionType: LambdaExpression,Expression: input1.loyalityFactor 3 AND input1.totalPurchasesToDate 50000 AND input1.totalPurchasesToDate 100000},{RuleName: OrHasHighNumberOfTotalOrders,ErrorMessage: One or more adjust rules failed.,ErrorType: Error,RuleExpressionType: LambdaExpression,Expression: input2.totalOrders 15}
]
}
示例可以从官方的代码库中下载示例定义了上述规则就可以直接开始用了。示例描述了这么一个应用场景根据不同的客户属性提供不同的折扣。由于销售的情况变化较快提供折扣的规则也需要经常变动。因此比较适用于规则引擎。Copypublic void Run()
{Console.WriteLine($Running {nameof(BasicDemo)}....);//创建输入var basicInfo {\name\: \hello\,\email\: \abcyxyz.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.DeserializeObjectExpandoObject(basicInfo, converter);dynamic input2 JsonConvert.DeserializeObjectExpandoObject(orderInfo, converter);dynamic input3 JsonConvert.DeserializeObjectExpandoObject(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.DeserializeObjectListWorkflowRules(fileData);//初始化规则引擎var bre new RulesEngine.RulesEngine(workflowRules.ToArray(), null);string discountOffered No discount offered.;//执行规则ListRuleResultTree resultList bre.ExecuteAllRulesAsync(Discount, inputs).Result;//处理结果resultList.OnSuccess((eventName) {discountOffered $Discount offered is {eventName} % over MRP.;});resultList.OnFail(() {discountOffered The user is not eligible for any discount.;});Console.WriteLine(discountOffered);
}
输入输入一般来说是IEnumerabledynamic或者是匿名类型上面实例展示的是由json反序列化形成的dynamic类型对于程序生成的数据使用匿名类型更加方便。Copyvar nestedInput new {SimpleProp simpleProp,NestedProp new {SimpleProp nestedSimpleProp,ListProp new ListListItem{new ListItem{Id 1,Value first},new ListItem{Id 2,Value second}}}};
命名空间和脚本引擎一样默认规则引擎只能访问System的命名空间。如果需要使用到稍微复杂一些的类型可以自己定义类型或者函数。比如定义一个这样的函数Copypublic static class Utils
{public static bool CheckContains(string check, string valList){if (String.IsNullOrEmpty(check) || String.IsNullOrEmpty(valList))return false;var list valList.Split(,).ToList();return list.Contains(check);}
}
需要使用的时候先将类传递给RulesEngineCopyvar reSettingsWithCustomTypes new ReSettings { CustomTypes new Type[] { typeof(Utils) } };
var engine new RulesEngine.RulesEngine(workflowRules.ToArray(), null, reSettingsWithCustomTypes);
然后就可以直接在表达式中使用了。CopyExpression: Utils.CheckContains(input1.country, \india,usa,canada,France\) true
规则参数默认情况下规则的输入使用的是类似input1 input2这样的形式如果想直观一点可以使用RuleParameter来进行封装具体的参数类型。CopyRuleParameter ruleParameter new RuleParameter(NIP, nestedInput);
var resultList bre.ExecuteAllRulesAsync(workflow.WorkflowName, ruleParameter).Result;
本地变量如果表达式比较复杂的情况下可以使用本地变量来进行分段处理这对调试来说会比较方便。本地变量的关键字为localParams可以将中间的内容简单理解成var name expressionCopy{name: allow_access_if_all_mandatory_trainings_are_done_or_access_isSecure,errorMessage: Please complete all your training(s) to get access to this content or access it from a secure domain/location.,errorType: Error,localParams: [{name: completedSecurityTrainings,expression: MasterSecurityComplainceTrainings.Where(Status.Equals(\Completed\, StringComparison.InvariantCultureIgnoreCase))},{name: completedProjectTrainings,expression: MasterProjectComplainceTrainings.Where(Status.Equals(\Completed\, StringComparison.InvariantCultureIgnoreCase))},{name: isRequestAccessSecured,expression: UserRequestDetails.Location.Country \India\ ? ((UserRequestDetails.Location.City \Bangalore\ UserRequestDetails.Domain\xxxx\)? true : false):false}],expression: (completedSecurityTrainings.Any() completedProjectTrainings.Any()) || isRequestAccessSecured }
总结使用规则引擎可以将经常变动的业务逻辑独立摘出来为我们编写动态、可拓展的程序提供了很大的便利。RulesEngine这个东西提供的API也比较简洁上手非常简单。