DEV Community

Cover image for Should approval thresholds live in your .NET workflow or in a rule engine?
Optimajet Limited
Optimajet Limited

Posted on

Should approval thresholds live in your .NET workflow or in a rule engine?

Keep approval thresholds in your .NET workflow while developers own them, the thresholds change about once a year, there are two or three of them, and one service uses them. Move them to a rule engine when a business owner wants to edit them without a developer. Do the same when the thresholds change quarterly or more often, when the list grows into a table, or when several services need the same decision. After the move, a workflow action calls the rule engine and stores the decision with its rule version.

Mike Lukinov, co-founder of Optimajet, sets out that rule in Rule Engine vs Workflow Engine. Mike writes from the workflow side. Workflow Engine by Optimajet is a .NET workflow engine with no rule engine of its own. The post compares Workflow Engine with the rule engines it would call: NRules, Microsoft RulesEngine and DMN (Decision Model and Notation) engines. Workflow Engine Free runs the workflow side of this pattern. It needs no license key. Its license covers personal use and internal commercial use, with attribution.

The product facts were checked on Workflow Engine 23.0.0 on 27 October 2026. The facts about NRules, Microsoft RulesEngine and DMN were checked on their own pages the same day. The thresholds in the examples are illustrative.

What a rule engine does and what a workflow engine does

A rule engine evaluates facts against explicit rules and returns a decision, usually without keeping state between calls. A workflow engine stores every running process and moves it from step to step. Take a purchase request for 60,000 from a preferred supplier. The rule engine answers that the request needs CFO approval. Workflow Engine then holds the request in its database, perhaps for days, until the CFO acts. The same supplier's request for 12,000 gets Auto-approve and finishes in the same call. When a request only needs an answer, such as a live checkout price, the rule engine alone is enough.

One name can mislead .NET readers. In Workflow Engine, a Rule is a permission check that decides which user may execute a command. It is not a business rule.

Three places a threshold can live

In Workflow Engine, a scheme describes a process. It defines the activities (steps), the transitions between them and the commands that people execute. A threshold has two homes inside the workflow and one outside it.

  1. An Expression condition in the scheme. By default, it is a C# expression that reads a process parameter. It sits on a transition. A change ships as a new scheme version. Running instances keep the version they started with until you migrate them.
  2. An Action condition in your code. Your IWorkflowActionProvider implements a named condition that can read the threshold from configuration or a table. A change needs no new scheme version, but a developer still owns the threshold. Nothing records which value routed each request.
  3. A rule engine. It sits outside the workflow. It takes the thresholds that business owners edit, that change quarterly or more often, that grow into tables, or that several services share.

Which rule engine for which rules

Workflow Engine's own Decision Table activity is not a rule engine. Each row holds a transition condition and a target activity. The rows are stored in the scheme. The activity has no hit policies and no repository for business users. A hit policy is the rule that picks the result when several rows match.

Decision tables that analysts edit belong in a DMN engine or a business rules management system (BRMS). Both store rules as data and version them. DMN, the decision standard of the Object Management Group, reached version 1.6 in September 2026. For rules that developers own, two MIT-licensed .NET libraries are common choices.

  • NRules (1.0.4, published 3 February 2026) runs rules that you write in C# with an internal DSL. So a rule change is normally a code change. The project also offers JSON serialization and a text rule language called Rule#. NRules can fire several matching rules and infer new facts.
  • Microsoft RulesEngine (6.0.1, published 3 July 2026) keeps rules as JSON outside the code. It suits rules that change as data but need no full rule repository.

Boundary tests catch row-order and threshold mistakes

Once a threshold moves from Workflow Engine to a rule engine's table, the order of the rows is part of the logic. Under the DMN First hit policy, the engine checks the rows in order and returns the first match.

Purchase approval routing, First hit policy (from the full post)

Rule order Supplier status Amount (USD) Route Reason
1 Blocked Any Reject Supplier is on the block list
2 Any ≥ 50,000 CFO approval Above executive threshold
3 New ≥ 5,000 Procurement review New supplier above review threshold
4 Preferred < 50,000 Auto-approve Preferred supplier under the limit
5 Any Any Manager approval Default route

If you move row 1 below row 2, a blocked supplier's request for 60,000 goes to the CFO instead of being rejected. If you raise row 2 to 75,000 and leave row 4 at 50,000, two other routes change by accident. A preferred supplier's request for 60,000 goes to the manager. A new supplier's request for 60,000 goes to procurement review instead of the CFO. Boundary tests at 49,999.99, 50,000, 74,999.99 and 75,000 catch both mistakes before release. When rows should never overlap, the DMN Unique hit policy turns an overlap into an error.

How a workflow action calls the rule engine

With Workflow Engine, the two engines connect through a contract. It says which facts go in, which decision and rule version come out, and what happens when the call is late or fails. A workflow action is the code that a step of the scheme runs. In this pattern, the action does four things.

  1. It reads the facts from the request's process parameters, such as the supplier status and the amount.
  2. It calls the rule service and gives the call its own deadline, for example 500 ms.
  3. It stores the route and the rule version as persistent parameters, which are saved with the request.
  4. When the call is late or fails, the action stores the decision NeedsReview and the reason instead.

Transitions with Expression conditions then route the request by the stored decision. Workflow Engine checks an Otherwise transition last. This transition sends all other requests to a step where a person reviews them. Requests with the decision NeedsReview go there too. When the call to the rule service is late or fails, even a request that the rules would approve waits for a person. The reason is stored as well.

Three things need care.

  • The deadline needs a call that can be canceled. The action passes a cancellation token to the call. An HTTP call to a rule service stops when the token fires. A rule engine inside the same application stops only if its API accepts the token. NRules checks the token between rule firings. Give any engine that ignores the token its own time limit.
  • A call that changes something can run twice. After a restart, the step can run again. Such a call needs an idempotency key or an outbox. An idempotency key is a value that makes a repeated call harmless. An outbox holds messages that are saved in the same database transaction and sent after the transaction commits. A call that only computes can simply run again.
  • A second engine is a second system. It adds a network call, its own ways to fail and its own release cycle for rules.

The stored rule version records which rules made the decision. It does not pin the request to those rules. Suppose a request is submitted before a threshold changes and is evaluated after the change. That request takes the new route. A threshold in an Expression condition is pinned for free, because each request keeps its scheme version. With a rule engine, the contract has to carry a version or a creation time. The rule service also has to keep old versions.

What it takes to run the contract on .NET

Workflow Engine Free includes actions, persistent parameters and Expression conditions, which is all the contract needs. It runs with up to 10 workflow definitions (schemes) and 4 execution threads. A public web application or a SaaS product needs the Subscription, SaaS or Enterprise Edition of Workflow Engine NEO. Workflow Engine NEO is the HTTP API product of the Workflow Engine Family.

So keep each threshold where its owner can change it. When a threshold moves to a rule engine, keep the route in the workflow and store the rule version with every decision. The full post adds a side-by-side table of the two engines. It also answers whether rules engines are outdated now that AI models score requests. Both are in Rule Engine vs Workflow Engine, and Where a Business Rules Engine Fits.

Top comments (0)