At the heart of every piece of enterprise software is its business logic, the code that analyzes inputs and creates appropriate outputs. It’s how we turn the steps of a business process into code, adding logic at every step in a workflow. That way we only need to write necessary code and we can avoid complexity.
Not all business logic is set in stone. Some processes, especially those that are key to a business’s finances are often driven by external rules and regulations that can change at short notice. For example, you might be calculating sales tax as part of an e-commerce service when government policies force a sudden change in the rate or how those rates are applied.
That could leave you suddenly having to pull resources from other projects to quickly develop new modules so that you’re ready to run as soon as the new regulations are in force. Development resources aren’t cheap, so what’s needed is a way of externalizing those rules and regulations so that you don’t need to change your code, only the rules that it uses.
The answer is an old one: the rules engine. Here input values are tested and simple rules applied, returning a result that indicates which rules have been triggered. The complex aspects of business logic can remain in their own modules and services; all that needs to change is rules engine configuration. So, for example, if a service needs to be called if a transaction is greater than $50, and the rules change to make that limit $45, all you need to do is edit and update the rule that calls the service and passes the transaction to it.
Introducing Microsoft Rules Engine
Microsoft has developed a relatively easy-to-use open source Rules Engine library for .NET applications, available as a NuGet package or from GitHub. Designed to provide a rule abstraction from your code, rules are stored outside your application as JSON with rules written using .NET’s familiar lambda expression syntax. An active community and regular updates make it a useful tool and well worth considering.
With its rules outside your code, you can change the rules at any time by simply uploading a new rules file and restarting your application. You can choose an appropriate store for your rules, with the best option for the platform you’re running on, for example, using MySQL on a web server, the file system on a PC, or an Azure Blob Storage account for an Azure App Service application.
Once you have added the Rules Engine library to your code, the engine parses the rules and input messages, returns the results to your application, and allows processing to continue based on the state delivered by the engine. The library itself sits outside your code, working as a referenced NuGet package with a wrapper to handle getting and caching the rules, as well as driving the rest of your application from the results of rule evaluations.
Building rules for the Rules Engine
Getting started with the .NET Rule Engine is relatively simple. You will need to first consider how to separate rules from your application and then how to describe them in lambda expressions. There are options for building your own custom rules using public classes that can be referred to from a lambda expression, an approach that gets around the limitations associated with lambda expressions only being able to use methods from .NET’s system namespace.
You can find a JSON schema for the rules in the project’s GitHub repository. It’s a comprehensive schema, but in practice, you’re likely to only need a basic structure for your rules. Start by giving your rules workflow a name and then following it up with a nested list of rules. Each rule needs a name, an event that’s raised if it’s successful, an error message and type, and a rule expression that’s defined as a lambda expression.
Your rule expression needs to be defined in terms of the inputs to the rules engine. Each input is an object, and the lambda function evaluates the various values associated with the input. Each value needs to be given a test, with tests part of a logical expression that, when evaluated as true, will trigger the rule’s success event. It’s a good idea to list all the rules you want to use in advance, along with the conditions that need to be met to trigger the rule. That way you can confirm that the rules you have defined meet your application’s use case in a way that makes them understandable by stakeholders.
To use the Rules Engine, first use a constructor to instantiate the library, loading the workflow rules as JSON. Once it’s up and running, getting results from the Rules Engine is a matter of calling it with a workflow name and the current inputs, getting the OnSuccess or OnFail events and using them in your application. A wiki provides detailed instructions for how to use the library.
Build your own rules editor
A useful tool to help build rules comes in the shape of a Blazor UI library that can edit new rules and export them in an appropriate format for your applications. You can build it into your own code so you can keep your rules development inside your firewall, or there’s a quick start in the shape of a WebAssembly-based Progressive Web App that developers can install on their own devices to build schema-compliant rules.
The PWA rules editor works in two modes. First, a workflow-driven view constructs rules using lambda expressions. The second option defines Input RuleParameters, which can give rules custom names. At the same time, you can use local parameters in a rule to break it into easier-to-understand elements with their own names that can then be combined into a single rule. For example, one local parameter can be associated with an expression that shows whether a specific input is a specific value, with another for a different input. The results associated with each local parameter can then be combined in a logical statement to determine whether the complete rule triggers or not.
By separating rules from code and using a web-based editor to create new rules, we can build a tool that lets business analysts modify rules without requiring developer input. This approach can save time and resources. It’s not quite rolling your own Power Platform-like tools, as you’re limiting the inputs and rules that can be edited, operating with many more constraints than the more freeform Power Platform. Even so, giving users some element of control in areas where changes are expected ensures that those changes are made in a timely fashion and developers don’t need to switch tasks on the fly.
Using a rules engine like this can simplify application workflow, externalizing your business logic and allowing rapid updates that other development methods and tools may prevent. Microsoft’s open source approach to .NET library development allows you to get into the code and make changes that support your business needs, as well as letting you take advantage of community-driven performance improvements and new features.