Galosys.Foundation.RulesEngine
26.5.20.1
dotnet add package Galosys.Foundation.RulesEngine --version 26.5.20.1
NuGet\Install-Package Galosys.Foundation.RulesEngine -Version 26.5.20.1
<PackageReference Include="Galosys.Foundation.RulesEngine" Version="26.5.20.1" />
<PackageVersion Include="Galosys.Foundation.RulesEngine" Version="26.5.20.1" />
<PackageReference Include="Galosys.Foundation.RulesEngine" />
paket add Galosys.Foundation.RulesEngine --version 26.5.20.1
#r "nuget: Galosys.Foundation.RulesEngine, 26.5.20.1"
#:package Galosys.Foundation.RulesEngine@26.5.20.1
#addin nuget:?package=Galosys.Foundation.RulesEngine&version=26.5.20.1
#tool nuget:?package=Galosys.Foundation.RulesEngine&version=26.5.20.1
Galosys.Foundation.RulesEngine
基于 Microsoft RulesEngine 的规则引擎封装,支持 6 种业务场景(折扣/分配/风控/运费/路由/价格),提供统一抽象层、执行模式分发、热更新、降级和可观测能力。
成熟度: 🟡 可用 — 重构中,API 可能变更
快速开始
1. 注入
services.AddRuleEngine(context.Configuration);
2. 配置
// appsettings.json
{
"Rules": {
"Path": "rules.json"
}
}
rules.json 示例:
{
"discount": [
{
"Code": "vip-discount",
"Name": "VIP会员折扣",
"Condition": "input.VipLevel >= 2 AND input.OrderAmount >= 500",
"Output": "new { Type = \"Percentage\", Value = 10m }",
"Priority": 100,
"Enabled": true,
"GroupCode": "MEMBER"
},
{
"Code": "new-user-discount",
"Name": "新用户首单优惠",
"Condition": "input.IsNewUser == true AND input.OrderAmount >= 100",
"Output": "new { Type = \"Fixed\", Value = 20m }",
"Priority": 90,
"Enabled": true,
"GroupCode": "PROMO"
}
]
}
3. 基本用法
var engine = serviceProvider.GetRequiredService<IRuleEngine>();
var result = await engine.ExecuteAsync("discount", new
{
VipLevel = 2,
OrderAmount = 800,
IsNewUser = false
});
if (result.Success)
{
foreach (var hit in result.Hits.Where(h => h.Matched))
{
Console.WriteLine($"命中规则: {hit.Code}, 输出: {hit.Output}");
}
}
业务场景示例
场景一:折扣/促销(ConflictResolve + GroupExclusive)
互斥组内只取最优折扣,跨组可叠加。
var result = await engine.ExecuteAsync("discount", cart, new RuleExecuteOption
{
Mode = RuleExecuteMode.ConflictResolve,
ConflictStrategy = ConflictStrategy.GroupExclusive
});
foreach (var group in result.Hits.Where(h => h.Matched).GroupBy(h => h.GroupCode))
{
Console.WriteLine($"组 {group.Key}: {group.First().Code} -> {group.First().Output}");
}
场景二:库存分配(FirstMatch + FallbackChain)
SKU 级参数 > 店铺级 > 全局级,参数回退链合并后用于分配规则。
var merged = FallbackChain.Merge<AllocationParams>(skuLevel, storeLevel, global);
var result = await engine.ExecuteAsync("allocation", new
{
SkuId = "SKU001",
RequestQty = 100,
AvailableStock = merged.MaxAllocate,
AllocatePct = merged.AllocatePct,
SafetyStock = merged.SafetyStock
}, new RuleExecuteOption
{
Mode = RuleExecuteMode.FirstMatch
});
if (result.Hits.FirstOrDefault(h => h.Matched) is { } hit)
{
Console.WriteLine($"分配策略: {hit.Code} -> {hit.Output}");
}
场景三:风控/欺诈检测(AllEvaluate + RiskScore)
全部规则执行,累加风控分数,超阈值触发告警。
var result = await engine.ExecuteAsync("risk", new
{
UserId = "U10086",
OrderAmount = 5000m,
IpAddress = "192.168.1.1",
DeviceFingerprint = "abc123",
OrderCount24h = 8
}, new RuleExecuteOption
{
ScoreThreshold = 80
});
Console.WriteLine($"风控总分: {result.TotalScore}, 是否拦截: {result.TotalScore >= 80}");
场景四:运费计算(AllEvaluate 附加费叠加)
多条附加费规则叠加计算总运费。
var result = await engine.ExecuteAsync("shipping", new
{
Region = "偏远地区",
Weight = 15.5m,
IsOversized = true,
IsFragile = true
});
decimal totalShipping = baseShippingFee;
foreach (var hit in result.Hits.Where(h => h.Matched))
{
var surcharge = JsonSerializer.Deserialize<SurchargeOutput>(hit.Output!);
totalShipping += surcharge.Amount;
}
场景五:订单路由(FirstMatch 三次调用)
分三次调用:仓库匹配 → 物流商匹配 → 特殊处理匹配。
var orderCtx = new { OrderId = "ORD001", Region = "华东", SkuCategory = "生鲜" };
var warehouse = await engine.ExecuteAsync("route-warehouse", orderCtx, new RuleExecuteOption
{
Mode = RuleExecuteMode.FirstMatch
});
var carrier = await engine.ExecuteAsync("route-carrier", orderCtx, new RuleExecuteOption
{
Mode = RuleExecuteMode.FirstMatch
});
var special = await engine.ExecuteAsync("route-special", orderCtx, new RuleExecuteOption
{
Mode = RuleExecuteMode.FirstMatch
});
场景六:价格引擎(FirstMatch 价格瀑布)
客户协议价 > 会员价 > 促销价 > 基准价,按优先级瀑布式匹配。
var result = await engine.ExecuteAsync("pricing", new
{
CustomerId = "C001",
SkuId = "SKU001",
CategoryCode = "ELECTRONICS",
IsVip = true,
IsPromoActive = true
}, new RuleExecuteOption
{
Mode = RuleExecuteMode.FirstMatch
});
if (result.Hits.FirstOrDefault(h => h.Matched) is { } priceHit)
{
var price = JsonSerializer.Deserialize<PriceOutput>(priceHit.Output!);
Console.WriteLine($"命中最优价格: {priceHit.Code}, 价格: {price.Amount}");
}
Fluent API 定义规则
var rule = RuleBuilder.Create()
.Code("vip-discount")
.Name("VIP会员折扣")
.RuleSet("discount")
.When("input.VipLevel >= 2 AND input.OrderAmount >= 500")
.Then("new { Type = \"Percentage\", Value = 10m }")
.Priority(100)
.Group("MEMBER")
.Tag("会员", "折扣")
.Build();
参数回退链(FallbackChain)
多层参数合并,高优先级覆盖低优先级的非 NULL 值。
var skuLevel = new AllocationParams { MaxAllocate = 200 };
var storeLevel = new AllocationParams { AllocatePct = 80, SafetyStock = 50 };
var global = new AllocationParams
{
StrategyType = "FIFO",
MaxAllocate = 0,
MinAllocate = 1,
AllocatePct = 100
};
var merged = FallbackChain.Merge<AllocationParams>(skuLevel, storeLevel, global);
// MaxAllocate=200(SKU), AllocatePct=80(店铺), SafetyStock=50(店铺),
// StrategyType=FIFO(全局), MinAllocate=1(全局)
热更新
{
"Rules": {
"Path": "rules.json",
"HotReload": true,
"HotReloadMode": "FileWatcher"
}
}
| 模式 | 说明 | 适用场景 |
|---|---|---|
FileWatcher |
监听配置文件变更(默认) | 单实例 / 开发环境 |
Redis |
Redis Pub/Sub 多实例同步 | 多实例部署(需 Redis 模块) |
Polling |
定时轮询版本比对 | 数据库规则源 |
降级
规则引擎不可用时自动降级,返回默认结果而不阻塞业务。
{
"Rules": {
"FallbackEnabled": true
}
}
降级时 RuleExecuteResult.Success = false,Hits 为空,Error 包含降级原因。
可观测性
事件监听
实现 IRuleEventListener 并标注 [Service] 自动注册:
[Service]
public class AuditRuleListener : IRuleEventListener
{
public Task OnBeforeEvaluateAsync(string ruleSet, object input) => Task.CompletedTask;
public Task OnRuleMatchedAsync(string ruleSet, RuleHit hit) => Task.CompletedTask;
public Task OnRuleFailedAsync(string ruleSet, RuleHit hit, Exception ex) => Task.CompletedTask;
public Task OnAfterEvaluateAsync(string ruleSet, RuleExecuteResult result) => Task.CompletedTask;
}
OpenTelemetry Metrics
| 指标 | 类型 | 标签 |
|---|---|---|
galosys.rules.execution.total |
Counter | rule_set |
galosys.rules.execution.duration |
Histogram | rule_set |
galosys.rules.match.total |
Counter | rule_set, rule_code |
galosys.rules.error.total |
Counter | rule_set, error_type |
配置参考
{
"Rules": {
"Path": "rules.json",
"HotReload": true,
"HotReloadMode": "FileWatcher",
"HotReloadInterval": "00:00:05",
"FallbackEnabled": true,
"MetricsEnabled": true
}
}
相关模块
| 模块 | 说明 | NuGet |
|---|---|---|
Galosys.Foundation.RulesEngine |
核心模块(本模块) | 必选 |
Galosys.Foundation.RulesEngine.EntityFrameworkCore |
数据库规则存储 | 可选 |
Galosys.Foundation.RulesEngine.Redis |
Redis Pub/Sub 热更新广播 | 可选 |
命名空间
所有抽象接口和模型位于 Microsoft.Extensions.Rules,调用方无需额外 using。
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Galosys.Foundation.Core (>= 26.5.20.1)
- rulesengine (>= 5.0.2)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Galosys.Foundation.RulesEngine:
| Package | Downloads |
|---|---|
|
Galosys.Foundation.RulesEngine.Redis
Galosys.Foundation快速开发库 |
|
|
Galosys.Foundation.RulesEngine.EntityFrameworkCore
Galosys.Foundation快速开发库 |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 26.5.20.1 | 121 | 5/20/2026 |
| 26.5.19.1 | 136 | 5/19/2026 |
| 26.5.18.1 | 135 | 5/18/2026 |
| 26.5.15.1 | 142 | 5/15/2026 |
| 26.5.12.3 | 125 | 5/12/2026 |
| 26.5.12.2 | 130 | 5/12/2026 |
| 26.4.27.1-rc1 | 94 | 4/26/2026 |
| 26.4.25.1-rc1 | 91 | 4/25/2026 |
| 26.4.22.2-rc7 | 97 | 4/22/2026 |
| 26.4.22.2-rc6 | 75 | 4/22/2026 |
| 26.4.22.2-rc4 | 93 | 4/22/2026 |
| 26.4.22.2-rc3 | 85 | 4/22/2026 |
| 26.4.19.1-rc1 | 92 | 4/19/2026 |
| 26.4.12.8-rc1 | 96 | 4/12/2026 |
| 26.4.12.7-rc1 | 98 | 4/12/2026 |
| 26.4.12.5-rc1 | 96 | 4/12/2026 |
| 26.1.30.1-rc1 | 110 | 1/30/2026 |
| 26.1.29.1 | 119 | 1/29/2026 |
| 26.1.28.5 | 114 | 1/28/2026 |
| 26.1.28.4 | 113 | 1/28/2026 |