diff --git a/Masa.Framework.sln b/Masa.Framework.sln index 29a9315ca..f202e503b 100644 --- a/Masa.Framework.sln +++ b/Masa.Framework.sln @@ -577,6 +577,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Service.Caller EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Authentication.OpenIdConnect.EFCore.Oracle", "src\Contrib\Authentication\OpenIdConnect\Masa.Contrib.Authentication.OpenIdConnect.EFCore.Oracle\Masa.Contrib.Authentication.OpenIdConnect.EFCore.Oracle.csproj", "{03F476EF-022A-4370-B1C3-FEEDE3BB4E7F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RulesEngine", "RulesEngine", "{A7081ADB-DB21-4678-8510-A5367D470743}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RulesEngine", "RulesEngine", "{8E74F3D4-9387-4F69-9A17-C793CE2CBAA9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.BuildingBlocks.RulesEngine", "src\BuildingBlocks\RulesEngine\Masa.BuildingBlocks.RulesEngine\Masa.BuildingBlocks.RulesEngine.csproj", "{B03C329C-70F4-442A-B420-90DDF7E31847}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.RulesEngine.MicrosoftRulesEngine", "src\Contrib\RulesEngine\Masa.Contrib.RulesEngine.MicrosoftRulesEngine\Masa.Contrib.RulesEngine.MicrosoftRulesEngine.csproj", "{4E217EC9-0616-414B-82D9-9107F9826D6E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3FADF704-2581-47AC-A1F7-07091B6328A1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests", "src\Contrib\RulesEngine\Tests\Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests\Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests.csproj", "{EEB2D542-5A2C-4E18-A0E6-72844C359DAD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2041,6 +2053,14 @@ Global {BEA8E5A5-E7BD-4165-80CD-D1F53ED82D02}.Release|Any CPU.Build.0 = Release|Any CPU {BEA8E5A5-E7BD-4165-80CD-D1F53ED82D02}.Release|x64.ActiveCfg = Release|Any CPU {BEA8E5A5-E7BD-4165-80CD-D1F53ED82D02}.Release|x64.Build.0 = Release|Any CPU + {B03C329C-70F4-442A-B420-90DDF7E31847}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B03C329C-70F4-442A-B420-90DDF7E31847}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B03C329C-70F4-442A-B420-90DDF7E31847}.Debug|x64.ActiveCfg = Debug|Any CPU + {B03C329C-70F4-442A-B420-90DDF7E31847}.Debug|x64.Build.0 = Debug|Any CPU + {B03C329C-70F4-442A-B420-90DDF7E31847}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B03C329C-70F4-442A-B420-90DDF7E31847}.Release|Any CPU.Build.0 = Release|Any CPU + {B03C329C-70F4-442A-B420-90DDF7E31847}.Release|x64.ActiveCfg = Release|Any CPU + {B03C329C-70F4-442A-B420-90DDF7E31847}.Release|x64.Build.0 = Release|Any CPU {03F476EF-022A-4370-B1C3-FEEDE3BB4E7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {03F476EF-022A-4370-B1C3-FEEDE3BB4E7F}.Debug|Any CPU.Build.0 = Debug|Any CPU {03F476EF-022A-4370-B1C3-FEEDE3BB4E7F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -2049,6 +2069,22 @@ Global {03F476EF-022A-4370-B1C3-FEEDE3BB4E7F}.Release|Any CPU.Build.0 = Release|Any CPU {03F476EF-022A-4370-B1C3-FEEDE3BB4E7F}.Release|x64.ActiveCfg = Release|Any CPU {03F476EF-022A-4370-B1C3-FEEDE3BB4E7F}.Release|x64.Build.0 = Release|Any CPU + {4E217EC9-0616-414B-82D9-9107F9826D6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E217EC9-0616-414B-82D9-9107F9826D6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E217EC9-0616-414B-82D9-9107F9826D6E}.Debug|x64.ActiveCfg = Debug|Any CPU + {4E217EC9-0616-414B-82D9-9107F9826D6E}.Debug|x64.Build.0 = Debug|Any CPU + {4E217EC9-0616-414B-82D9-9107F9826D6E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E217EC9-0616-414B-82D9-9107F9826D6E}.Release|Any CPU.Build.0 = Release|Any CPU + {4E217EC9-0616-414B-82D9-9107F9826D6E}.Release|x64.ActiveCfg = Release|Any CPU + {4E217EC9-0616-414B-82D9-9107F9826D6E}.Release|x64.Build.0 = Release|Any CPU + {EEB2D542-5A2C-4E18-A0E6-72844C359DAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EEB2D542-5A2C-4E18-A0E6-72844C359DAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EEB2D542-5A2C-4E18-A0E6-72844C359DAD}.Debug|x64.ActiveCfg = Debug|Any CPU + {EEB2D542-5A2C-4E18-A0E6-72844C359DAD}.Debug|x64.Build.0 = Debug|Any CPU + {EEB2D542-5A2C-4E18-A0E6-72844C359DAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EEB2D542-5A2C-4E18-A0E6-72844C359DAD}.Release|Any CPU.Build.0 = Release|Any CPU + {EEB2D542-5A2C-4E18-A0E6-72844C359DAD}.Release|x64.ActiveCfg = Release|Any CPU + {EEB2D542-5A2C-4E18-A0E6-72844C359DAD}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2332,7 +2368,13 @@ Global {9BB5CC86-C2E8-4859-9610-50DB263605A3} = {FC4A0C94-47F7-4C9A-A7EC-138DE8EB842D} {8D7D3D21-86DB-4FCC-8FF0-6E1587ABD22A} = {FC4A0C94-47F7-4C9A-A7EC-138DE8EB842D} {BEA8E5A5-E7BD-4165-80CD-D1F53ED82D02} = {8D7D3D21-86DB-4FCC-8FF0-6E1587ABD22A} + {A7081ADB-DB21-4678-8510-A5367D470743} = {950DA7D0-48C1-42BA-8E8F-F72C0DCE41C4} {03F476EF-022A-4370-B1C3-FEEDE3BB4E7F} = {41769FBF-91A8-48D1-B3BB-CAE4C814E7CD} + {8E74F3D4-9387-4F69-9A17-C793CE2CBAA9} = {DC578D74-98F0-4F19-A230-CFA8DAEE0AF1} + {B03C329C-70F4-442A-B420-90DDF7E31847} = {8E74F3D4-9387-4F69-9A17-C793CE2CBAA9} + {4E217EC9-0616-414B-82D9-9107F9826D6E} = {A7081ADB-DB21-4678-8510-A5367D470743} + {3FADF704-2581-47AC-A1F7-07091B6328A1} = {A7081ADB-DB21-4678-8510-A5367D470743} + {EEB2D542-5A2C-4E18-A0E6-72844C359DAD} = {3FADF704-2581-47AC-A1F7-07091B6328A1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {40383055-CC50-4600-AD9A-53C14F620D03} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data.Contracts/Options/MasaRelationOptions.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data.Contracts/Options/MasaRelationOptions.cs index 3bfcfa841..ac9845f3c 100644 --- a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data.Contracts/Options/MasaRelationOptions.cs +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data.Contracts/Options/MasaRelationOptions.cs @@ -1,6 +1,8 @@ // Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ReSharper disable once CheckNamespace + namespace Masa.BuildingBlocks.Data; public class MasaRelationOptions diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data.Contracts/Response/ResponseBase.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data.Contracts/Response/ResponseBase.cs new file mode 100644 index 000000000..e53de7aa0 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data.Contracts/Response/ResponseBase.cs @@ -0,0 +1,17 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data.Contracts.Response; + +public class ResponseBase +{ + public bool IsValid { get; } + + public string Message { get; } + + public ResponseBase(bool isValid, string message = "") + { + IsValid = isValid; + Message = message; + } +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/DefaultRulesEngineFactory.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/DefaultRulesEngineFactory.cs new file mode 100644 index 000000000..33ea461e4 --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/DefaultRulesEngineFactory.cs @@ -0,0 +1,23 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.RulesEngine; + +public class DefaultRulesEngineFactory : MasaFactoryBase, + IRulesEngineFactory +{ + protected override string DefaultServiceNotFoundMessage + => $"No default {nameof(IRulesEngineClient)} found, you may need services.AddRulesEngine(options => options.UseRulesEngine())"; + + protected override string SpecifyServiceNotFoundMessage + => $"Please make sure you have used [{0}] {nameof(IRulesEngineClient)}, it was not found"; + + protected override MasaFactoryOptions FactoryOptions => _options.Value; + + private readonly IOptions _options; + + public DefaultRulesEngineFactory(IServiceProvider serviceProvider) : base(serviceProvider) + { + _options = serviceProvider.GetRequiredService>(); + } +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/IRulesEngineClient.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/IRulesEngineClient.cs new file mode 100644 index 000000000..671d38cc5 --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/IRulesEngineClient.cs @@ -0,0 +1,32 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.RulesEngine; + +public interface IRulesEngineClient +{ + /// + /// Check if the rule format is correct + /// + /// + /// + VerifyResponse Verify(string ruleRaw); + + /// + /// Obtain whether the match is successful according to the rules and input parameters + /// + /// + /// Input data + /// + /// Whether the match was successful + List Execute(string ruleRaw, TRequest data); + + /// + /// Obtain whether the match is successful according to the rules and input parameters + /// + /// Rule Json + /// Input data + /// + /// Whether the match was successful + Task> ExecuteAsync(string ruleRaw, TRequest data); +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/IRulesEngineFactory.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/IRulesEngineFactory.cs new file mode 100644 index 000000000..36d1463db --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/IRulesEngineFactory.cs @@ -0,0 +1,9 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.RulesEngine; + +public interface IRulesEngineFactory : IMasaFactory +{ + +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Masa.BuildingBlocks.RulesEngine.csproj b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Masa.BuildingBlocks.RulesEngine.csproj new file mode 100644 index 000000000..b3d41f5ba --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Masa.BuildingBlocks.RulesEngine.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Options/RulesEngineFactoryOptions.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Options/RulesEngineFactoryOptions.cs new file mode 100644 index 000000000..5b578d38b --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Options/RulesEngineFactoryOptions.cs @@ -0,0 +1,17 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +// ReSharper disable once CheckNamespace + +namespace Masa.BuildingBlocks.RulesEngine; + +public class RulesEngineFactoryOptions : MasaFactoryOptions +{ + public void TryAddRulesEngine(string name, Func func) + { + if (Options.Any(opt => opt.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) + return; + + Options.Add(new RulesEngineRelationOptions(name, func)); + } +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Options/RulesEngineOptions.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Options/RulesEngineOptions.cs new file mode 100644 index 000000000..68ef78e49 --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Options/RulesEngineOptions.cs @@ -0,0 +1,15 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +// ReSharper disable once CheckNamespace +namespace Masa.BuildingBlocks.RulesEngine; + +public class RulesEngineOptions +{ + public IServiceCollection Services { get; } + + public RulesEngineOptions(IServiceCollection services) + { + Services = services; + } +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Options/RulesEngineRelationOptions.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Options/RulesEngineRelationOptions.cs new file mode 100644 index 000000000..30759107b --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Options/RulesEngineRelationOptions.cs @@ -0,0 +1,15 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +// ReSharper disable once CheckNamespace + +namespace Masa.BuildingBlocks.RulesEngine; + +public class RulesEngineRelationOptions : MasaRelationOptions +{ + public RulesEngineRelationOptions(string name, Func func) + : base(name) + { + Func = func; + } +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Response/ActionResponse.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Response/ActionResponse.cs new file mode 100644 index 000000000..4cf2cce21 --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Response/ActionResponse.cs @@ -0,0 +1,11 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.RulesEngine; + +public class ActionResponse +{ + public object Output { get; set; } + + public Exception Exception { get; set; } +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Response/ExecuteResponse.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Response/ExecuteResponse.cs new file mode 100644 index 000000000..b846ef8da --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Response/ExecuteResponse.cs @@ -0,0 +1,19 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.RulesEngine; + +public class ExecuteResponse : ResponseBase +{ + public string RuleName { get; set; } + + public string SuccessEvent { get; set; } + + public ActionResponse ActionResult { get; set; } + + public ExecuteResponse(string ruleName, bool isValid, string message = "") + : base(isValid, message) + { + RuleName = ruleName; + } +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Response/VerifyResponse.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Response/VerifyResponse.cs new file mode 100644 index 000000000..96c1e84fc --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/Response/VerifyResponse.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.RulesEngine; + +public class VerifyResponse : ResponseBase +{ + public VerifyResponse(bool isValid, string message = "") + : base(isValid, message) + { + } +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/RulesEngineClientBase.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/RulesEngineClientBase.cs new file mode 100644 index 000000000..4b088afa8 --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/RulesEngineClientBase.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.RulesEngine; + +public abstract class RulesEngineClientBase : IRulesEngineClient +{ + public abstract VerifyResponse Verify(string ruleRaw); + + public abstract List Execute(string ruleRaw, TRequest data); + + public abstract Task> ExecuteAsync(string ruleRaw, TRequest data); +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/ServiceCollectionExtensions.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..b3d3dce2e --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/ServiceCollectionExtensions.cs @@ -0,0 +1,19 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +// ReSharper disable once CheckNamespace + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddRulesEngine(this IServiceCollection services, Action action) + { + MasaApp.TrySetServiceCollection(services); + services.TryAddSingleton(); + services.TryAddTransient(serviceProvider => serviceProvider.GetRequiredService().Create()); + RulesEngineOptions rulesEngineOptions = new RulesEngineOptions(services); + action.Invoke(rulesEngineOptions); + return services; + } +} diff --git a/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/_Imports.cs b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/_Imports.cs new file mode 100644 index 000000000..99ae8642e --- /dev/null +++ b/src/BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/_Imports.cs @@ -0,0 +1,9 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +global using Masa.BuildingBlocks.Data; +global using Masa.BuildingBlocks.Data.Contracts.Response; +global using Masa.BuildingBlocks.RulesEngine; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.DependencyInjection.Extensions; +global using Microsoft.Extensions.Options; diff --git a/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/Internal/Constant.cs b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/Internal/Constant.cs new file mode 100644 index 000000000..0f8325cba --- /dev/null +++ b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/Internal/Constant.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +// ReSharper disable once CheckNamespace +namespace Masa.Contrib.RulesEngine.MicrosoftRulesEngine; + +internal static class Constant +{ + public const string DEFAULT_JSON_NAME = "Masa.Contrib.RulesEngine.MicrosoftRulesEngine"; + + public const string ERROR_RULE = "illegal rules on MicrosoftRulesEngine"; +} diff --git a/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.csproj b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.csproj new file mode 100644 index 000000000..73d670eb7 --- /dev/null +++ b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/README.md b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/README.md new file mode 100644 index 000000000..d688b3a8a --- /dev/null +++ b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/README.md @@ -0,0 +1,118 @@ +[中](README.zh-CN.md) | EN + +## Masa.Contrib.RulesEngine.MicrosoftRulesEngine + +A rules engine implemented based on [`RulesEngine`](https://github.com/microsoft/RulesEngine), It provides a simple way of giving you the ability to put your rules in a store outside the core logic of the system, thus ensuring that any change in rules don't affect the core system. + +Example: + +``` powershell +Install-Package Masa.Contrib.RulesEngine.MicrosoftRulesEngine //Use the rule engine provided by microsoft +``` + +### getting Started + +1. Register `RulesEngine`, modify `Program.cs` + +``` C# +builder.Services.AddRulesEngine(rulesEngineOptions => +{ + rulesEngineOptions.UseMicrosoftRulesEngine(); +}) +``` + +2. Use Rule Engine Client ([`IRulesEngineClient`](../../../BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/IRulesEngineClient.cs)) + +``` C# +IRulesEngineClient rulesEngineClient; //Get from DI + +var json = @"{ + ""WorkflowName"": ""UserInputWorkflow"",// Not required + ""Rules"": [ + { + ""RuleName"": ""CheckAge"", + ""ErrorMessage"": ""Must be over 18 years old."", + ""ErrorType"": ""Error"", + ""RuleExpressionType"": ""LambdaExpression"", + ""Expression"": ""Age > 18"" + } + ] +}";//rule json + +var result = rulesEngineClient.Execute(ruleJson, new +{ + Age = 19 +}); +Console.WriteLine("The result of the rule execution is {0}", result[0].IsValid); +``` + +### Advanced + +### Extended supported methods + +The default rule engine does not support methods other than the `System` namespace, but you can support other methods by changing the default configuration + +1. Create a new `StringUtils` class to extend string methods and provide extension methods for the rule engine + +``` C# +public static class StringUtils +{ + public static bool IsNullOrEmpty(this string? value) + => string.IsNullOrEmpty(value); +} +``` + +2. Register `RulesEngine`, and extend to support the methods provided by `StringUtils` class, modify `Program.cs` + +``` C# +builder.Services.AddRulesEngine(rulesEngineOptions => +{ + rulesEngineOptions.UseMicrosoftRulesEngine(new ReSettings() + { + CustomTypes = new[] { typeof(StringUtils) } + }); +}) +``` + +### There are multiple rule engines with different configurations + +Supports multiple completely different rule engines, such as: + +1. Register `RulesEngine`, and specify `name` for the current rules engine + +The following example registers two rule engines. The default rule engine only supports methods using the `System` namespace. The rule engine named `ruleA` supports the methods in the `StringUtils` class in addition to the methods in the `System` namespace. extension method + +``` C# +builder.Services.AddRulesEngine(rulesEngineOptions => +{ + rulesEngineOptions.UseMicrosoftRulesEngine(); + rulesEngineOptions.UseMicrosoftRulesEngine("ruleA", new ReSettings() + { + CustomTypes = new[] { typeof(StringUtils) } + }); +}) +``` + +2. Use the specified rule engine + +* Use the rule engine named `ruleA` + +``` C# +IRulesEngineFactory rulesEngineFactory; // get from DI +var rulesEngineClient = rulesEngineFactory.Create("ruleA"); +``` + +* Use the default rule engine + +You can directly get the default rule engine Client through DI + +``` C# +IRulesEngineClient rulesEngineClient; //Get from DI (the directly obtained rule engine Client is the default) +``` + +Or get it through the rule engine factory + +``` C# +IRulesEngineFactory rulesEngineFactory; // get from DI +rulesEngineClient = rulesEngineFactory.Create(); +``` \ No newline at end of file diff --git a/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/README.zh-CN.md b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/README.zh-CN.md new file mode 100644 index 000000000..9d20fe43e --- /dev/null +++ b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/README.zh-CN.md @@ -0,0 +1,118 @@ +中 | [EN](README.md) + +## Masa.Contrib.RulesEngine.MicrosoftRulesEngine + +基于[`RulesEngine`](https://github.com/microsoft/RulesEngine)实现的规则引擎,它提供了一种简单的方法,使您能够将规则放在系统核心逻辑之外的存储中,从而确保规则的任何更改都不会影响核心系统 + +用例: + +``` powershell +Install-Package Masa.Contrib.RulesEngine.MicrosoftRulesEngine //使用 microsoft 提供的规则引擎 +``` + +### 入门 + +1. 注册`RulesEngine`, 修改`Program.cs` + +``` C# +builder.Services.AddRulesEngine(rulesEngineOptions => +{ + rulesEngineOptions.UseMicrosoftRulesEngine(); +}) +``` + +2. 使用规则引擎Client ([`IRulesEngineClient`](../../../BuildingBlocks/RulesEngine/Masa.BuildingBlocks.RulesEngine/IRulesEngineClient.cs)) + +``` C# +IRulesEngineClient rulesEngineClient; //从DI获取 + +var json = @"{ + ""WorkflowName"": ""UserInputWorkflow"",// 非必填 + ""Rules"": [ + { + ""RuleName"": ""CheckAge"", + ""ErrorMessage"": ""Must be over 18 years old."", + ""ErrorType"": ""Error"", + ""RuleExpressionType"": ""LambdaExpression"", + ""Expression"": ""Age > 18"" + } + ] +}";//规则json + +var result = rulesEngineClient.Execute(ruleJson, new +{ + Age = 19 +}); +Console.WriteLine("规则执行结果为{0}", result[0].IsValid); +``` + +### 进阶 + +### 扩展支持的方法 + +默认规则引擎不支持除`System`命名空间以外的方法,但你可以通过更改默认配置支持其它方法 + +1. 新建`StringUtils`类,用于扩展字符串方法,并为规则引擎中提供扩展方法 + +``` C# +public static class StringUtils +{ + public static bool IsNullOrEmpty(this string? value) + => string.IsNullOrEmpty(value); +} +``` + +2. 注册`RulesEngine`, 并扩展支持`StringUtils`类提供的方法, 修改`Program.cs` + +``` C# +builder.Services.AddRulesEngine(rulesEngineOptions => +{ + rulesEngineOptions.UseMicrosoftRulesEngine(new ReSettings() + { + CustomTypes = new[] { typeof(StringUtils) } + }); +}) +``` + +### 存在多个不同配置的规则引擎 + +支持多个完全不同的规则引擎,例如: + +1. 注册`RulesEngine`, 并为当前规则引擎指定`name` + +下面示例注册了两个规则引擎,默认规则引擎仅支持使用`System`命名空间的方法,name为`ruleA`的规则引擎除了支持`System`命名空间的方法之外还支持`StringUtils`类下的扩展方法 + +``` C# +builder.Services.AddRulesEngine(rulesEngineOptions => +{ + rulesEngineOptions.UseMicrosoftRulesEngine(); + rulesEngineOptions.UseMicrosoftRulesEngine("ruleA", new ReSettings() + { + CustomTypes = new[] { typeof(StringUtils) } + }); +}) +``` + +2. 使用指定的规则引擎 + +* 使用name为`ruleA`的规则引擎 + +``` C# +IRulesEngineFactory rulesEngineFactory; // 从DI获取 +var rulesEngineClient = rulesEngineFactory.Create("ruleA"); +``` + +* 使用默认的规则引擎 + +你可以通过DI直接获取到默认的规则引擎Client + +``` C# +IRulesEngineClient rulesEngineClient; //从DI获取 (直接获取到的规则引擎Client是默认的) +``` + +或者通过规则引擎工厂获取 + +``` C# +IRulesEngineFactory rulesEngineFactory; // 从DI获取 +rulesEngineClient = rulesEngineFactory.Create(); +``` \ No newline at end of file diff --git a/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/RulesEngineClient.cs b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/RulesEngineClient.cs new file mode 100644 index 000000000..ddb6d4ae7 --- /dev/null +++ b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/RulesEngineClient.cs @@ -0,0 +1,73 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.RulesEngine.MicrosoftRulesEngine; + +extern alias MicrosoftRulesEngine; +using MicrosoftRulesEngine::RulesEngine; +using MicrosoftRulesEngine::RulesEngine.Models; + +public class RulesEngineClient : RulesEngineClientBase +{ + private readonly RulesEngine _rulesEngine; + private readonly ILogger? _logger; + + public RulesEngineClient(ReSettings? reSettings = null, ILogger? logger = null) + { + _rulesEngine = new RulesEngine(Array.Empty(), reSettings); + _logger = logger; + } + + public override VerifyResponse Verify(string ruleRaw) + { + try + { + if (JsonConvert.DeserializeObject(ruleRaw) == null) + { + return new VerifyResponse(false, "illegal rules"); + } + return new VerifyResponse(true); + } + catch (Exception ex) + { + _logger?.LogWarning(ex, Constant.ERROR_RULE); + return new VerifyResponse(false, ex.Message); + } + } + + public override List Execute(string ruleRaw, TRequest data) + => ExecuteAsync(ruleRaw, data).ConfigureAwait(false).GetAwaiter().GetResult(); + + public override async Task> ExecuteAsync(string ruleRaw, TRequest data) + { + CheckAndAddRule(ruleRaw, out Workflow? workflow); + + var ruleResultTrees = await _rulesEngine.ExecuteAllRulesAsync(workflow!.WorkflowName, data); + return ConvertToExecuteResponse(ruleResultTrees); + } + + private void CheckAndAddRule(string ruleRaw, out Workflow? workflow) + { + _rulesEngine.ClearWorkflows(); + workflow = JsonConvert.DeserializeObject(ruleRaw); + if (workflow == null) + throw new UserFriendlyException(Constant.ERROR_RULE); + + if (string.IsNullOrWhiteSpace(workflow.WorkflowName)) + workflow.WorkflowName = Guid.NewGuid().ToString(); + _rulesEngine.AddWorkflow(workflow); + } + + private static List ConvertToExecuteResponse(List resultTrees) + { + return resultTrees.Select(result => new ExecuteResponse(result.Rule.RuleName, result.IsSuccess, result.ExceptionMessage) + { + SuccessEvent = result.Rule.SuccessEvent, + ActionResult = new ActionResponse() + { + Exception = result.ActionResult.Exception, + Output = result.ActionResult.Output + } + }).ToList(); + } +} diff --git a/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/RulesEngineOptionsExtensions.cs b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/RulesEngineOptionsExtensions.cs new file mode 100644 index 000000000..5a44a1c88 --- /dev/null +++ b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/RulesEngineOptionsExtensions.cs @@ -0,0 +1,33 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +extern alias MicrosoftRulesEngine; +using global::Masa.Contrib.RulesEngine.MicrosoftRulesEngine; +using MicrosoftRulesEngine::RulesEngine.Models; + +// ReSharper disable once CheckNamespace + +namespace Microsoft.Extensions.DependencyInjection; + +public static class RulesEngineOptionsExtensions +{ + public static RulesEngineOptions UseMicrosoftRulesEngine(this RulesEngineOptions rulesEngineOptions) + => rulesEngineOptions.UseMicrosoftRulesEngine(Options.Options.DefaultName); + + public static RulesEngineOptions UseMicrosoftRulesEngine(this RulesEngineOptions rulesEngineOptions, ReSettings? reSettings) + => rulesEngineOptions.UseMicrosoftRulesEngine(Options.Options.DefaultName, reSettings); + + public static RulesEngineOptions UseMicrosoftRulesEngine( + this RulesEngineOptions rulesEngineOptions, + string name, + ReSettings? reSettings = null) + { + rulesEngineOptions.Services.Configure(name, options => + { + options.TryAddRulesEngine(name, + serviceProvider => new RulesEngineClient(reSettings, serviceProvider.GetService>()) + ); + }); + return rulesEngineOptions; + } +} diff --git a/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/_Imports.cs b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/_Imports.cs new file mode 100644 index 000000000..32d09f9d8 --- /dev/null +++ b/src/Contrib/RulesEngine/Masa.Contrib.RulesEngine.MicrosoftRulesEngine/_Imports.cs @@ -0,0 +1,6 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +global using Masa.BuildingBlocks.RulesEngine; +global using Microsoft.Extensions.Logging; +global using Newtonsoft.Json; diff --git a/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests.csproj b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests.csproj new file mode 100644 index 000000000..539e31c19 --- /dev/null +++ b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests.csproj @@ -0,0 +1,37 @@ + + + + net6.0 + enable + enable + false + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + Always + + + + diff --git a/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/1.json b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/1.json new file mode 100644 index 000000000..a6b5d0ac6 --- /dev/null +++ b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/1.json @@ -0,0 +1,12 @@ +{ + "WorkflowName": "UserInputWorkflow", + "Rules": [ + { + "RuleName": "CheckAge", + "ErrorMessage": "Must be over 18 years old.", + "ErrorType": "Error", + "RuleExpressionType": "LambdaExpression", + "Expression": "Age > 18" + } + ] +} \ No newline at end of file diff --git a/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/2.json b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/2.json new file mode 100644 index 000000000..87ede8395 --- /dev/null +++ b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/2.json @@ -0,0 +1,12 @@ +{ + "WorkflowName": "UserInputWorkflow", + "Rules": [ + { + "RuleName": "CheckNameIsNotNullOrEmpty", + "ErrorMessage": "Name is not equal to null or empty.", + "ErrorType": "Error", + "RuleExpressionType": "LambdaExpression", + "Expression": "!Name.IsNullOrEmpty()" + } + ] +} \ No newline at end of file diff --git a/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/3.json b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/3.json new file mode 100644 index 000000000..ee58f781a --- /dev/null +++ b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/3.json @@ -0,0 +1,10 @@ +{ + "WorkflowName": "UserInputWorkflow", + "Rules": { + "RuleName": "CheckNameIsNotNullOrEmpty", + "ErrorMessage": "Name is not equal to null or empty.", + "ErrorType": "Error", + "RuleExpressionType": "LambdaExpression", + "Expression": "!Name.IsNullOrEmpty()" + } +} \ No newline at end of file diff --git a/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/4.json b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/4.json new file mode 100644 index 000000000..74ca300b7 --- /dev/null +++ b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/Rules/4.json @@ -0,0 +1,11 @@ +{ + "Rules": [ + { + "RuleName": "CheckNameIsNotNullOrEmpty", + "ErrorMessage": "Name is not equal to null or empty.", + "ErrorType": "Error", + "RuleExpressionType": "LambdaExpression", + "Expression": "!Name.IsNullOrEmpty()" + } + ] +} \ No newline at end of file diff --git a/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/RulesEngineClientTest.cs b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/RulesEngineClientTest.cs new file mode 100644 index 000000000..f37a672a9 --- /dev/null +++ b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/RulesEngineClientTest.cs @@ -0,0 +1,59 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +using Microsoft.Extensions.Logging; + +namespace Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests; + +[TestClass] +public class RulesEngineClientTest +{ + [TestMethod] + public void TestExecute() + { + var rulesEngineClient = new RulesEngineClient(); + var json = File.ReadAllText(Path.Combine("Rules", "1.json")); + var result = rulesEngineClient.Execute(json, new + { + Age = 16 + }); + Assert.IsFalse(result[0].IsValid); + } + + [TestMethod] + public async Task TestExecuteAsync() + { + var rulesEngineClient = new RulesEngineClient(); + var json = await File.ReadAllTextAsync(Path.Combine("Rules", "1.json")); + var result = await rulesEngineClient.ExecuteAsync(json, new + { + Age = 19 + }); + Assert.IsTrue(result[0].IsValid); + } + + [DataRow("3.json", false)] + [DataRow("1.json", true)] + [DataTestMethod] + public void TestVerify(string fileName, bool expectResult) + { + var rulesEngineClient = new RulesEngineClient(); + var json = File.ReadAllText(Path.Combine("Rules", fileName)); + var result = rulesEngineClient.Verify(json); + Assert.AreEqual(expectResult, result.IsValid); + } + + [DataRow("3.json", false)] + [DataRow("1.json", true)] + [DataTestMethod] + public void TestVerifyAndUseLogger(string fileName, bool expectResult) + { + var services = new ServiceCollection(); + services.AddLogging(builder => builder.AddConsole()); + var serviceProvider = services.BuildServiceProvider(); + var rulesEngineClient = new RulesEngineClient(logger: serviceProvider.GetRequiredService>()); + var json = File.ReadAllText(Path.Combine("Rules", fileName)); + var result = rulesEngineClient.Verify(json); + Assert.AreEqual(expectResult, result.IsValid); + } +} diff --git a/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/RulesEngineTest.cs b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/RulesEngineTest.cs new file mode 100644 index 000000000..d1002264b --- /dev/null +++ b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/RulesEngineTest.cs @@ -0,0 +1,105 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests; + +[TestClass] +public class RulesEngineTest +{ + [TestMethod] + public void TestAddRulesEngine() + { + var services = new ServiceCollection(); + services.AddRulesEngine(rulesEngineOptions => + { + rulesEngineOptions.UseMicrosoftRulesEngine(); + }); + var serviceProvider = services.BuildServiceProvider(); + var ruleEngineFactory = serviceProvider.GetService(); + Assert.IsNotNull(ruleEngineFactory); + var ruleEngineClient = serviceProvider.GetService(); + Assert.IsNotNull(ruleEngineClient); + } + + [TestMethod] + public void TestAddRulesEngine2() + { + var services = new ServiceCollection(); + services.AddRulesEngine(rulesEngineOptions => + { + rulesEngineOptions.UseMicrosoftRulesEngine(new ReSettings() + { + CustomTypes = new[] { typeof(StringExtensions) } + }); + }); + var serviceProvider = services.BuildServiceProvider(); + var ruleEngineClient = serviceProvider.GetService(); + Assert.IsNotNull(ruleEngineClient); + + var json = File.ReadAllText(Path.Combine("Rules", "2.json")); + var result = ruleEngineClient.Execute(json, new + { + Name = string.Empty + }); + Assert.IsFalse(result[0].IsValid); + + json = File.ReadAllText(Path.Combine("Rules", "1.json")); + result = ruleEngineClient.Execute(json, new + { + Age = 19 + }); + Assert.IsTrue(result[0].IsValid); + } + + [DataRow("", false)] + [DataRow(null, false)] + [DataRow("Jim", true)] + [DataTestMethod] + public void TestAddRulesEngineAndSpecifyRuleSettings(string? name, bool expectResult) + { + var services = new ServiceCollection(); + services.AddRulesEngine(rulesEngineOptions => + { + rulesEngineOptions.UseMicrosoftRulesEngine(new ReSettings() + { + CustomTypes = new[] { typeof(StringExtensions) } + }); + }); + var serviceProvider = services.BuildServiceProvider(); + var ruleEngineClient = serviceProvider.GetService(); + Assert.IsNotNull(ruleEngineClient); + + var json = File.ReadAllText(Path.Combine("Rules", "2.json")); + var result = ruleEngineClient.Execute(json, new + { + Name = name + }); + Assert.AreEqual(expectResult, result[0].IsValid); + } + + [DataRow("", false)] + [DataRow(null, false)] + [DataRow("Jim", true)] + [DataTestMethod] + public void TestAddRulesEngineAndSpecifyRuleSettings2(string? name, bool expectResult) + { + var services = new ServiceCollection(); + services.AddRulesEngine(rulesEngineOptions => + { + rulesEngineOptions.UseMicrosoftRulesEngine(new ReSettings() + { + CustomTypes = new[] { typeof(StringExtensions) } + }); + }); + var serviceProvider = services.BuildServiceProvider(); + var ruleEngineClient = serviceProvider.GetService(); + Assert.IsNotNull(ruleEngineClient); + + var json = File.ReadAllText(Path.Combine("Rules", "4.json")); + var result = ruleEngineClient.Execute(json, new + { + Name = name + }); + Assert.AreEqual(expectResult, result[0].IsValid); + } +} diff --git a/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/_Imports.cs b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/_Imports.cs new file mode 100644 index 000000000..48ecc22f3 --- /dev/null +++ b/src/Contrib/RulesEngine/Tests/Masa.Contrib.RulesEngine.MicrosoftRulesEngine.Tests/_Imports.cs @@ -0,0 +1,8 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +global using Masa.BuildingBlocks.RulesEngine; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.Logging; +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using RulesEngine.Models;