I've been working a bit lately with the Workflow Foundation Rules Engine. It's just too cool not to blog something about it.
The whole idea behind the rules engine and where it's value lies is that you can update and create rules on the fly outside of your compiled assemblies. All of your rules (if/and/or/else logic) get serialized to an ASCII XML file that can be stored anywhere. This is great for rapidly changing business environments where instead of calling IT and doing a development cycle, a business guy can fire up an editor and start changing the way the application works.
Get Started
The API for the Rules Engine is included with the .NET framework 3.0, but can be used totally independently of Workflow.
I recommend these two articles to get some good samples running to where you can run through and debug and get some sense of what's happening:
http://richardsbraindump.blogspot.com/2007/08/how-to-use-windows-workflow-rules.html
http://odetocode.com/Blogs/scott/archive/2006/10/01/7293.aspx
And this demo is a good one to grab (from the netfx3 site):
http://wf.netfx3.com/files/folders/rules_samples/entry309.aspx
How to update the rules
The link above to the demo at netfx3.com has included with it a kind of "crude" rule editor. I found it pretty painless to use, but I'm not so sure about a business guy with no dev experience. The cool thing about the engine is that it is completely open. Here is one 3rd party tool available(that I could find easily) InRule.
Speed
If you go out on the net and Google for this topic you're going to find tons of insanely in depth articles about WF rules vs. Biztalk BRE (Business Rules Engine). In the end the winner is the BRE, but the only way you're going to notice more than a trivial performance difference is if you're running millions and millions of requests simultaneously. For most situations WF rules are going to give you sufficient performance.
Technique
The only real challenge for me in getting started was figuring out what the best technique was for using the rules engine. Here's my take...
Essentially you are passing the rules engine a simple .NET object. Any decisions that you want the rule engine to make have to be stored within that object. What I found it easiest to do is create methods that make it easy for the user to add results that will be easy to read by the application after the engine has been ran.
So here's the way I've found easiest to design and implement the rules engine.
1) Create a simple .NET class that will hold all of your "facts". These facts are the data that will allow you (or your business user) to evaluate from the rules engine (via a GUI rules editor). I imagine using a translation class to take your true business objects and pull certain properties and collections over to a newly instantiated class to pass to the engine.
2) Think of how your business user is going to use the rule editor. Any method that you write in the class being passed to the rule engine can be called from the rules designer. You can use these methods to add shortcuts or allow the user to perform more complex operations as the rules execute.
3) Add attributes to the rule sets that allow you to filter which rule sets apply to the problem you are trying to solve. These attributes will be used to filter only applicable rule sets when you go to run the rules engine. This is also where you can 'version' your rulesets. Use these version columns to keep a history of the way the rulesets have changed over time. ("RuleSet" here is a custom object that I am using to store the rule-xml and data about the rule set.)
When you have your collection of RuleSet objects, loop through and allow the rules engine to evaluate them:
The 'c' object below is the custom object that I am using to hold all the facts to send to the rule engine.
List<BusinessRuleRecord> ruleSets = dbm.getBusinessRuleRecordsWhere("Insert SQL Query Here -- AND VersionMajor = 1 AND VersionMinor = 0");
RuleSetService svc = new RuleSetService();
foreach (RuleData.BusinessRuleRecord rule in ruleSets)
{
RuleSet ruleset = svc.GetRuleSet(new RuleSetInfo(rule.Name)); //RuleSet = System.Workflow.Activities.Rules object.
RuleExecution exec = new RuleExecution(new RuleValidation(c.GetType(), null), c);
ruleset.Execute(exec);
}
So what this did is went out to my database and grabbed all the rulesets that applied to my data and executed them. Pretty simple implementation - but I think the key to keeping the performance up is only selectively running your rules.
I think that Workflow and the rules engine is some of the neatest technology that's been released lately. I hope to be spending a lot more time in these namespaces in the next few months trying to learn when it would be appropriate to use this technology in real world scenarios.
0 comments:
Post a Comment