Users/abcy/libupdate (#496)
* updated dependencies * - Improved global param compilation for multiple rules * update version number * updated the changelogpull/498/head v5.0.0
parent
caf41e3cd3
commit
47e7809591
|
@ -2,6 +2,13 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [5.0.0]
|
||||
- Fixed security bug related to System.Dynamic.Linq.Core
|
||||
|
||||
### Breaking Changes
|
||||
- As a part of security bug fix, method call for only registered types via reSettings will be allowed. This only impacts strongly typed inputs and nested types
|
||||
|
||||
|
||||
## [4.0.0]
|
||||
- RulesEngine is now available in both dotnet 6 and netstandard 2.0
|
||||
- Dependency on ILogger, MemoryCache have been removed
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
|
||||
<!--<PackageReference Include="RulesEngine" Version="3.0.2" />-->
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -37,7 +37,9 @@ namespace RulesEngine.ExpressionBuilders
|
|||
}
|
||||
public Expression Parse(string expression, ParameterExpression[] parameters, Type returnType)
|
||||
{
|
||||
var config = new ParsingConfig { CustomTypeProvider = new CustomTypeProvider(_reSettings.CustomTypes) };
|
||||
var config = new ParsingConfig {
|
||||
CustomTypeProvider = new CustomTypeProvider(_reSettings.CustomTypes)
|
||||
};
|
||||
return new ExpressionParser(parameters, expression, new object[] { }, config).Parse(returnType);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RulesEngine.Extensions
|
||||
{
|
||||
internal static class EnumerableExtensions
|
||||
{
|
||||
public static IEnumerable<T> Safe<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
return enumerable ?? Enumerable.Empty<T>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,23 @@ namespace RulesEngine.Models
|
|||
[ExcludeFromCodeCoverage]
|
||||
public class ReSettings
|
||||
{
|
||||
|
||||
public ReSettings() { }
|
||||
|
||||
// create a copy of settings
|
||||
internal ReSettings(ReSettings reSettings)
|
||||
{
|
||||
CustomTypes = reSettings.CustomTypes;
|
||||
CustomActions = reSettings.CustomActions;
|
||||
EnableExceptionAsErrorMessage = reSettings.EnableExceptionAsErrorMessage;
|
||||
IgnoreException = reSettings.IgnoreException;
|
||||
EnableFormattedErrorMessage = reSettings.EnableFormattedErrorMessage;
|
||||
EnableScopedParams = reSettings.EnableScopedParams;
|
||||
NestedRuleExecutionMode = reSettings.NestedRuleExecutionMode;
|
||||
CacheConfig = reSettings.CacheConfig;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the custom types to be used in Rule expressions
|
||||
/// </summary>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
@ -31,6 +33,8 @@ namespace RulesEngine.Models
|
|||
}
|
||||
public IEnumerable<string> WorkflowsToInject { get; set; }
|
||||
|
||||
public RuleExpressionType RuleExpressionType { get; set; } = RuleExpressionType.LambdaExpression;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the global params which will be applicable to all rules
|
||||
/// </summary>
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace RulesEngine
|
|||
/// <param name="input"></param>
|
||||
/// <param name="ruleParam"></param>
|
||||
/// <returns>Compiled func delegate</returns>
|
||||
internal RuleFunc<RuleResultTree> CompileRule(Rule rule, RuleParameter[] ruleParams, ScopedParam[] globalParams)
|
||||
internal RuleFunc<RuleResultTree> CompileRule(Rule rule, RuleExpressionType ruleExpressionType, RuleParameter[] ruleParams, Lazy<RuleExpressionParameter[]> globalParams)
|
||||
{
|
||||
if (rule == null)
|
||||
{
|
||||
|
@ -56,10 +56,12 @@ namespace RulesEngine
|
|||
}
|
||||
try
|
||||
{
|
||||
var globalParamExp = GetRuleExpressionParameters(rule.RuleExpressionType,globalParams, ruleParams);
|
||||
var globalParamExp = globalParams.Value;
|
||||
var extendedRuleParams = ruleParams.Concat(globalParamExp.Select(c => new RuleParameter(c.ParameterExpression.Name,c.ParameterExpression.Type)))
|
||||
.ToArray();
|
||||
var ruleExpression = GetDelegateForRule(rule, extendedRuleParams);
|
||||
|
||||
|
||||
return GetWrappedRuleFunc(rule,ruleExpression,ruleParams,globalParamExp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -100,7 +102,7 @@ namespace RulesEngine
|
|||
return GetWrappedRuleFunc(rule, ruleFn, ruleParams, scopedParamList);
|
||||
}
|
||||
|
||||
private RuleExpressionParameter[] GetRuleExpressionParameters(RuleExpressionType ruleExpressionType,IEnumerable<ScopedParam> localParams, RuleParameter[] ruleParams)
|
||||
internal RuleExpressionParameter[] GetRuleExpressionParameters(RuleExpressionType ruleExpressionType,IEnumerable<ScopedParam> localParams, RuleParameter[] ruleParams)
|
||||
{
|
||||
if(!_reSettings.EnableScopedParams)
|
||||
{
|
||||
|
@ -227,6 +229,12 @@ namespace RulesEngine
|
|||
return (isSuccess, resultList);
|
||||
}
|
||||
|
||||
internal Func<object[],Dictionary<string,object>> CompileScopedParams(RuleExpressionType ruleExpressionType, RuleParameter[] ruleParameters,RuleExpressionParameter[] ruleExpParams)
|
||||
{
|
||||
return GetExpressionBuilder(ruleExpressionType).CompileScopedParams(ruleParameters, ruleExpParams);
|
||||
|
||||
}
|
||||
|
||||
private RuleFunc<RuleResultTree> GetWrappedRuleFunc(Rule rule, RuleFunc<RuleResultTree> ruleFunc,RuleParameter[] ruleParameters,RuleExpressionParameter[] ruleExpParams)
|
||||
{
|
||||
if(ruleExpParams.Length == 0)
|
||||
|
|
|
@ -7,6 +7,7 @@ using Newtonsoft.Json.Linq;
|
|||
using RulesEngine.Actions;
|
||||
using RulesEngine.Exceptions;
|
||||
using RulesEngine.ExpressionBuilders;
|
||||
using RulesEngine.Extensions;
|
||||
using RulesEngine.HelperFunctions;
|
||||
using RulesEngine.Interfaces;
|
||||
using RulesEngine.Models;
|
||||
|
@ -48,7 +49,7 @@ namespace RulesEngine
|
|||
|
||||
public RulesEngine(ReSettings reSettings = null)
|
||||
{
|
||||
_reSettings = reSettings ?? new ReSettings();
|
||||
_reSettings = reSettings == null ? new ReSettings(): new ReSettings(reSettings);
|
||||
if(_reSettings.CacheConfig == null)
|
||||
{
|
||||
_reSettings.CacheConfig = new MemCacheConfig();
|
||||
|
@ -286,9 +287,16 @@ namespace RulesEngine
|
|||
if (workflow != null)
|
||||
{
|
||||
var dictFunc = new Dictionary<string, RuleFunc<RuleResultTree>>();
|
||||
_reSettings.CustomTypes = _reSettings.CustomTypes.Safe().Union(ruleParams.Select(c => c.Type)).ToArray();
|
||||
// add separate compilation for global params
|
||||
|
||||
var globalParamExp = new Lazy<RuleExpressionParameter[]>(
|
||||
() => _ruleCompiler.GetRuleExpressionParameters(workflow.RuleExpressionType, workflow.GlobalParams, ruleParams)
|
||||
);
|
||||
|
||||
foreach (var rule in workflow.Rules.Where(c => c.Enabled))
|
||||
{
|
||||
dictFunc.Add(rule.RuleName, CompileRule(rule, ruleParams, workflow.GlobalParams?.ToArray()));
|
||||
dictFunc.Add(rule.RuleName, CompileRule(rule,workflow.RuleExpressionType, ruleParams, globalParamExp));
|
||||
}
|
||||
|
||||
_rulesCache.AddOrUpdateCompiledRule(compileRulesKey, dictFunc);
|
||||
|
@ -313,12 +321,15 @@ namespace RulesEngine
|
|||
{
|
||||
throw new ArgumentException($"Workflow `{workflowName}` does not contain any rule named `{ruleName}`");
|
||||
}
|
||||
return CompileRule(currentRule, ruleParameters, workflow.GlobalParams?.ToArray());
|
||||
var globalParamExp = new Lazy<RuleExpressionParameter[]>(
|
||||
() => _ruleCompiler.GetRuleExpressionParameters(workflow.RuleExpressionType, workflow.GlobalParams, ruleParameters)
|
||||
);
|
||||
return CompileRule(currentRule,workflow.RuleExpressionType, ruleParameters, globalParamExp);
|
||||
}
|
||||
|
||||
private RuleFunc<RuleResultTree> CompileRule(Rule rule, RuleParameter[] ruleParams, ScopedParam[] scopedParams)
|
||||
private RuleFunc<RuleResultTree> CompileRule(Rule rule, RuleExpressionType ruleExpressionType, RuleParameter[] ruleParams, Lazy<RuleExpressionParameter[]> scopedParams)
|
||||
{
|
||||
return _ruleCompiler.CompileRule(rule, ruleParams, scopedParams);
|
||||
return _ruleCompiler.CompileRule(rule, ruleExpressionType, ruleParams, scopedParams);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
|
||||
<Version>4.0.0</Version>
|
||||
<Version>5.0.0</Version>
|
||||
<Copyright>Copyright (c) Microsoft Corporation.</Copyright>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageProjectUrl>https://github.com/microsoft/RulesEngine</PackageProjectUrl>
|
||||
|
@ -31,12 +31,12 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FastExpressionCompiler" Version="3.3.3" />
|
||||
<PackageReference Include="FluentValidation" Version="11.2.2" />
|
||||
<PackageReference Include="FastExpressionCompiler" Version="3.3.4" />
|
||||
<PackageReference Include="FluentValidation" Version="11.5.2" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.Linq" Version="4.3.0" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.22" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.3" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -388,10 +388,12 @@ namespace RulesEngine.UnitTest
|
|||
[InlineData("rules6.json")]
|
||||
public async Task ExecuteRule_RuleWithMethodExpression_ReturnsSucess(string ruleFileName)
|
||||
{
|
||||
var re = GetRulesEngine(ruleFileName);
|
||||
|
||||
Func<bool> func = () => true;
|
||||
|
||||
var re = GetRulesEngine(ruleFileName, new ReSettings {
|
||||
CustomTypes = new[] { typeof(Func<bool>) }
|
||||
});
|
||||
|
||||
dynamic input1 = new ExpandoObject();
|
||||
input1.Property1 = "hello";
|
||||
input1.Boolean = false;
|
||||
|
@ -851,7 +853,7 @@ namespace RulesEngine.UnitTest
|
|||
}
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
private class TestInstanceUtils
|
||||
public class TestInstanceUtils
|
||||
{
|
||||
public bool CheckExists(string str)
|
||||
{
|
||||
|
|
|
@ -28,8 +28,8 @@ namespace RulesEngine.UnitTest
|
|||
var reSettings = new ReSettings();
|
||||
var parser = new RuleExpressionParser(reSettings);
|
||||
var compiler = new RuleCompiler(new RuleExpressionBuilderFactory(reSettings, parser),null);
|
||||
Assert.Throws<ArgumentNullException>(() => compiler.CompileRule(null, null,null));
|
||||
Assert.Throws<ArgumentNullException>(() => compiler.CompileRule(null, new RuleParameter[] { null },null));
|
||||
Assert.Throws<ArgumentNullException>(() => compiler.CompileRule(null, RuleExpressionType.LambdaExpression,null,null));
|
||||
Assert.Throws<ArgumentNullException>(() => compiler.CompileRule(null, RuleExpressionType.LambdaExpression, new RuleParameter[] { null },null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
<DelaySign>True</DelaySign>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoFixture" Version="4.17.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="System.Text.Json" Version="6.0.6" />
|
||||
<PackageReference Include="AutoFixture" Version="4.18.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="System.Text.Json" Version="7.0.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -101,6 +101,7 @@ namespace RulesEngine.UnitTest
|
|||
[Theory]
|
||||
[InlineData("GlobalParamsOnly")]
|
||||
[InlineData("LocalParamsOnly2")]
|
||||
[InlineData("GlobalParamsOnlyWithComplexInput")]
|
||||
public async Task ErrorInScopedParam_ShouldAppearAsErrorMessage(string workflowName)
|
||||
{
|
||||
var workflow = GetWorkflowList();
|
||||
|
@ -386,9 +387,13 @@ namespace RulesEngine.UnitTest
|
|||
new Rule {
|
||||
RuleName = "TrueTest",
|
||||
Expression = "globalParam1 == \"hello\""
|
||||
},
|
||||
new Rule {
|
||||
RuleName = "TrueTest2",
|
||||
Expression = "globalParam1.ToUpper() == \"HELLO\""
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue