Overview
Masterly.BusinessRules is a business rule engine for .NET. You write each rule, such as "an order must contain at least one item", as a small named unit with a code and a message. You then check one rule or many, and you get back a clear list of every rule that failed.
Every feature works with both synchronous and asynchronous rules. The one exception is specifications: an expression tree has no async form, so you use .ToAsync() to run a specification in async code (see Specifications and database queries). The core package has no dependencies. Five optional packages add text expressions, logging and tracing, dependency injection, feature management and test tools.
How it works
Working with rules has four stages. Each stage builds on the one before it, and every stage works the same way for sync and async rules. Select a stage to read its guide.
- DefineA rule has a code, a message and a condition. It is broken when the condition is true.
BaseBusinessRuleBusinessRuleBuilderBaseBusinessRule<T> - ComposeCombine small rules into bigger ones. A combined rule is still just a rule.
.And() . Or() . Not() RuleGroup.All / Any RuleGroup.AtLeast(n) - RunCheck one rule, or a whole batch with options for severity, faults and observers.
rule.Check() BusinessRuleChecker.CheckAll BusinessRuleChecker.EvaluateAll - UnderstandGet every broken rule with its details, or a tree of the whole evaluation.
BusinessRuleResultRuleEvaluationResultrule.Explain()
What you can do
- Write rulesA small class, an inline lambda, or one stateless rule for every subject.
- Combine rulesAnd, Or and Not, or groups such as "all", "any" and "at least 2 of".
- Check many at onceCheck many rules in one call. Collect every failure or stop at the first one.
- Explain failuresSee exactly which part of a combined rule failed, as a printable tree.
- Conditional and cachedRun a rule only when a condition holds, and cache the verdict of a slow rule.
- Shadow rolloutShip a rule in shadow mode behind a flag, then enforce it for a percentage of callers.
- Per-tenant limitsGive each tenant its own limits, such as a maximum order amount, without changing code.
- Query the databaseUse the same rule to check one object in memory and to find every violating row.
- Text expressionsWrite amount > @maxOrderAmount as text and see the values it was evaluated with.
- Logs, traces, metricsLog, trace and measure every evaluation with ILogger, OpenTelemetry and metrics.
- Dependency injectionRegister your rules in a DI container by assembly scanning and inject one runner.
- Test your rulesAssert verdicts, measure outcome coverage, find boundaries, run property checks.
Where to go next
- New hereQuick StartDefine two rules, check one, then check both together.
- See it in contextReal-world examplesCheckout, user registration, API validation and multi-tenant approval.
- Coming from 2.xUpgrading from 2.xWhy 3.0 needs a rebuild, and which behaviours changed.
- Looking something upAPI referenceEvery public type and member, one package at a time.