GoRules.Zen
0.5.0
dotnet add package GoRules.Zen --version 0.5.0
NuGet\Install-Package GoRules.Zen -Version 0.5.0
<PackageReference Include="GoRules.Zen" Version="0.5.0" />
<PackageVersion Include="GoRules.Zen" Version="0.5.0" />
<PackageReference Include="GoRules.Zen" />
paket add GoRules.Zen --version 0.5.0
#r "nuget: GoRules.Zen, 0.5.0"
#:package GoRules.Zen@0.5.0
#addin nuget:?package=GoRules.Zen&version=0.5.0
#tool nuget:?package=GoRules.Zen&version=0.5.0
GoRules.Zen
A cross-platform .NET binding for GoRules Zen - a high-performance business rules engine written in Rust.
🚀 安装
Step 1: 安装主包
dotnet add package GoRules.Zen
Step 2: 安装平台原生包
GoRules.Zen 需要对应平台的原生库才能运行。请根据你的目标平台选择:
| 平台 | 安装命令 |
|---|---|
| Windows x64 | dotnet add package GoRules.Zen.Native.win-x64 |
| macOS x64 | dotnet add package GoRules.Zen.Native.osx-x64 |
| macOS ARM64 (Apple Silicon) | dotnet add package GoRules.Zen.Native.osx-arm64 |
| Linux x64 | dotnet add package GoRules.Zen.Native.linux-x64 |
| Linux ARM64 | dotnet add package GoRules.Zen.Native.linux-arm64 |
例如,在 macOS Apple Silicon 上:
dotnet add package GoRules.Zen
dotnet add package GoRules.Zen.Native.osx-arm64
⚠️ 注意: 如果没有安装对应的原生包,运行时会收到清晰的错误提示,告知需要安装哪个包。
📋 支持的平台
| 平台 | 架构 |
|---|---|
| Windows | x64 |
| macOS | x64, ARM64 (Apple Silicon) |
| Linux | x64, ARM64 |
📖 目录
快速开始
using GoRules.Zen;
// 1. 创建引擎(带文件加载器)
var options = new ZenEngineOptions
{
Loader = path => File.ReadAllBytesAsync($"rules/{path}")
};
using var engine = new ZenEngine(options);
// 2. 执行决策
var result = await engine.Evaluate<MyResult>("my-rule.json", new { input = 42 });
// 3. 使用结果
Console.WriteLine($"输出: {result.Result}");
ZenEngine 使用
创建引擎
无 Loader 模式(需手动传入决策内容)
using var engine = new ZenEngine();
// 读取决策文件
var decisionContent = await File.ReadAllBytesAsync("my-rule.json");
// 创建决策对象
using var decision = engine.CreateDecision(decisionContent);
// 执行决策
var result = await decision.Evaluate<MyOutput>(new { input = 15 });
使用自定义 Loader
Loader 允许按需加载决策文件,支持从文件系统、数据库、远程 API 等任意来源获取:
// 从文件系统加载
var options = new ZenEngineOptions
{
Loader = async path =>
{
var filePath = Path.Combine("Rules", path);
return await File.ReadAllBytesAsync(filePath);
}
};
using var engine = new ZenEngine(options);
// 直接通过 key 执行,引擎会自动调用 Loader
var result = await engine.Evaluate<MyOutput>("subfolder/my-rule.json", new { input = 10 });
// 从数据库加载
var options = new ZenEngineOptions
{
Loader = async key =>
{
using var db = new MyDbContext();
var rule = await db.Rules.FirstOrDefaultAsync(r => r.Key == key);
return Encoding.UTF8.GetBytes(rule.JsonContent);
}
};
使用自定义节点处理
CustomNodeHandler 允许你在决策流程中处理自定义节点类型:
var options = new ZenEngineOptions
{
Loader = path => File.ReadAllBytesAsync($"rules/{path}"),
CustomNodeHandler = async request =>
{
Console.WriteLine($"处理自定义节点: {request.Kind}");
Console.WriteLine($"输入数据: {request.Input}");
// 根据节点类型执行不同逻辑
return request.Kind switch
{
"httpCall" => new CustomNodeResponse
{
Output = await CallExternalApi(request.Input)
},
"dbQuery" => new CustomNodeResponse
{
Output = await QueryDatabase(request.Input)
},
_ => new CustomNodeResponse
{
Output = new { error = "Unknown node type" }
}
};
}
};
using var engine = new ZenEngine(options);
执行决策
使用 Evaluate
// 基本执行
var result = await engine.Evaluate<MyOutput>("rule.json", new { input = 42 });
Console.WriteLine(result.Result); // 获取结果
// 带 Trace 执行(用于调试)
var result = await engine.Evaluate<MyOutput>(
"rule.json",
new { input = 42 },
new ZenEvaluationOptions { Trace = true }
);
if (result.Trace != null)
{
Console.WriteLine($"执行跟踪: {result.Trace}");
}
使用 GetDecision 获取决策对象
// 获取可复用的决策对象
using var decision = await engine.GetDecision("rule.json");
// 多次执行同一决策
var result1 = await decision.Evaluate<MyOutput>(new { input = 10 });
var result2 = await decision.Evaluate<MyOutput>(new { input = 20 });
var result3 = await decision.Evaluate<MyOutput>(new { input = 30 });
安全执行(不抛异常)
使用 SafeEvaluate 和 SafeGetDecision 返回 ZenSafeResult,不会抛出异常:
// 安全执行决策
var result = await engine.SafeEvaluate<MyOutput>("rule.json", new { input = 42 });
if (result.Success)
{
Console.WriteLine($"成功: {result.Data?.Result}");
}
else
{
Console.WriteLine($"失败: {result.Error}");
}
// 使用 Unwrap 方法
var data = result.UnwrapOr(new MyOutput { Value = "默认值" }); // 失败返回默认值
var dataOrDefault = result.UnwrapOrDefault(); // 失败返回 null
var dataOrThrow = result.Unwrap(); // 失败抛异常
// 安全获取决策
var decisionResult = await engine.SafeGetDecision("rule.json");
if (decisionResult.Success)
{
using var decision = decisionResult.Data!;
var evalResult = await decision.Evaluate<MyOutput>(new { input = 10 });
}
ZenDecision 使用
ZenDecision 是预加载的决策对象,适合多次执行同一决策:
using var engine = new ZenEngine();
// 从 JSON 内容创建决策
var jsonContent = await File.ReadAllBytesAsync("rule.json");
using var decision = engine.CreateDecision(jsonContent);
// 执行决策
var result = await decision.Evaluate<MyOutput>(new { input = 15 });
// 带选项执行
var resultWithTrace = await decision.Evaluate<MyOutput>(
new { input = 15 },
new ZenEvaluationOptions
{
Trace = true,
MaxDepth = 10
}
);
ZenExpression 使用
ZenExpression 提供独立的表达式求值功能,无需创建引擎。
表达式求值
// 简单算术表达式
var sum = await ZenExpression.Evaluate<int>("1 + 2 + 3", null);
Console.WriteLine(sum); // 6
// 带上下文的表达式
var result = await ZenExpression.Evaluate<int>(
"price * quantity * (1 - discount)",
new { price = 100, quantity = 5, discount = 0.1 }
);
Console.WriteLine(result); // 450
// 字符串操作
var greeting = await ZenExpression.Evaluate<string>(
"'Hello, ' + name + '!'",
new { name = "World" }
);
Console.WriteLine(greeting); // "Hello, World!"
// 数组操作
var filtered = await ZenExpression.Evaluate<int[]>(
"filter(numbers, # > 10)",
new { numbers = new[] { 5, 10, 15, 20, 25 } }
);
// 结果: [15, 20, 25]
一元表达式
一元表达式用于条件判断,返回布尔值:
// 比较表达式
var isGreater = await ZenExpression.EvaluateUnary(
"> 100",
new Dictionary<string, object> { { "$", 150 } }
);
Console.WriteLine(isGreater); // true
// 包含判断
var isInList = await ZenExpression.EvaluateUnary(
"'US', 'CN', 'JP'",
new Dictionary<string, object> { { "$", "CN" } }
);
Console.WriteLine(isInList); // true
// 范围判断
var inRange = await ZenExpression.EvaluateUnary(
"[18..65]",
new Dictionary<string, object> { { "$", 30 } }
);
Console.WriteLine(inRange); // true
模板求值
模板使用 {{ }} 语法进行变量插值:
// 简单模板
var message = await ZenExpression.EvaluateTemplate(
"Hello, {{ name }}!",
new { name = "Alice" }
);
Console.WriteLine(message); // "Hello, Alice!"
// 多变量模板
var email = await ZenExpression.EvaluateTemplate(
"Dear {{ firstName }} {{ lastName }}, your order #{{ orderId }} has been shipped.",
new { firstName = "John", lastName = "Doe", orderId = 12345 }
);
// 带表达式的模板
var invoice = await ZenExpression.EvaluateTemplate(
"Total: ${{ price * quantity }}",
new { price = 9.99, quantity = 3 }
);
Console.WriteLine(invoice); // "Total: $29.97"
评估选项
ZenEvaluationOptions 用于控制决策执行行为:
var options = new ZenEvaluationOptions
{
// 启用执行跟踪(用于调试)
Trace = true,
// 或使用 TraceMode 枚举
TraceMode = TraceMode.Default, // None 或 Default
// 最大递归深度(防止无限循环)
MaxDepth = 10
};
var result = await engine.Evaluate<MyOutput>("rule.json", context, options);
错误处理
使用异常处理
try
{
var result = await engine.Evaluate<MyOutput>("rule.json", context);
}
catch (ZenException ex)
{
Console.WriteLine($"Zen 错误: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"其他错误: {ex.Message}");
}
使用 SafeResult
var result = await engine.SafeEvaluate<MyOutput>("rule.json", context);
if (!result.Success)
{
// 记录日志,返回默认值等
logger.Error($"决策执行失败: {result.Error}");
return defaultResponse;
}
return result.Data!.Result;
完整示例
ASP.NET Core 集成
// Program.cs
builder.Services.AddSingleton(sp =>
{
var env = sp.GetRequiredService<IWebHostEnvironment>();
return new ZenEngineOptions
{
Loader = async path =>
{
var rulesPath = Path.Combine(env.ContentRootPath, "Rules", path);
return await File.ReadAllBytesAsync(rulesPath);
}
};
});
builder.Services.AddSingleton(sp =>
{
var options = sp.GetRequiredService<ZenEngineOptions>();
return new ZenEngine(options);
});
// Controller
[ApiController]
[Route("api/[controller]")]
public class PricingController : ControllerBase
{
private readonly ZenEngine _engine;
public PricingController(ZenEngine engine)
{
_engine = engine;
}
[HttpPost("calculate")]
public async Task<IActionResult> Calculate([FromBody] PricingInput input)
{
var result = await _engine.SafeEvaluate<PricingOutput>(
"pricing-rules.json",
input
);
if (!result.Success)
{
return BadRequest(new { error = result.Error });
}
return Ok(result.Data?.Result);
}
}
折扣计算示例
public class DiscountService
{
private readonly ZenEngine _engine;
public DiscountService()
{
_engine = new ZenEngine(new ZenEngineOptions
{
Loader = path => File.ReadAllBytesAsync(Path.Combine("Rules", path))
});
}
public async Task<decimal> CalculateDiscount(Order order)
{
var context = new
{
totalAmount = order.TotalAmount,
customerType = order.Customer.Type,
itemCount = order.Items.Count,
isHoliday = DateTime.Now.DayOfWeek == DayOfWeek.Saturday
};
var result = await _engine.Evaluate<DiscountResult>(
"discount-rules.json",
context
);
return result.Result.DiscountPercent;
}
}
public record DiscountResult
{
public decimal DiscountPercent { get; init; }
public string? Reason { get; init; }
}
📚 更多资源
📄 许可证
MIT License - 详见 LICENSE
| 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 is compatible. 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 is compatible. 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. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.