Tracking Business Rules Called Outside of BizTalk

So I’m a big of the Business Rules Engine that ships with BizTalk Server. When you call into the rules engine from a BizTalk Orchestration using the “Call Rules” shape, you are able to track all the details of rule execution in the BizTalk Health and Activity Tracking tool. Sweet.

However, the Rules Engine is not BizTalk specific and has no dependencies on BizTalk assemblies or components.You can write any service or component that uses it (note the licensing considerations when putting the Rules Engine dll on client machines, however).But, if I just call the Rules Engine directly in code, how can I still get that valuable tracking information? Tracking information can be very important in a rules engine because we want to know WHO calls the rules so that we can determine rule dependencies and execution frequency. The one solution that I have here is to roll your own tracking. I’m using a simple XML file as my log store, but naturally you’d want to utilize something more robust like a database, or even an MSMQ as an intermediary.

So step 1 is to build your .NET fact classes. These are the objects that we will use when evaluating rules. The Rules Engine is pretty powerful as I can build a ruleset with any combination of .NET objects, XML documents, and database tables.In my case, I’m building two facts: (1) the first holds my business data (here, a credit request), and (2) holds context data about the rule execution (who called it, time stamp, etc), and a single method which logs the rule firing. Go ahead and strong name and GAC those assemblies so that the Rules Engine can use them.

During development, change the AssemblyInfo.cs file in the .NET facts assembly to have a hard coded version (e.g. 1.0.0). This way, making changes to the fact will still require updating the GAC, but, it doesn’t require rebuilding the rules to “use” the updated version.Much easier.

I then build my actual rule in the Rules Composer.Mine here is pretty simple … if the credit scores are good, and, the amount is reasonable, then go ahead and approve the request. I have a “negation” rule that handles the failure of any of those conditions. In the rule result I call the method contained in the second .NET fact to log the rule execution details.

Next I build an ASP.NET web service that will actually call this rule policy directly. Again, I have no need to use BizTalk to call the rule here if I don’t want to. My web service project has a reference to both my facts assembly, and a reference to the Microsoft.RulesEngine.dll.

The code looks like this …

public bool CallCreditCheckRule(string callingApp, int custID, decimal amount, int score1, int score2)
//create create object from input params
CreditAppFact ca = new CreditAppFact();
ca.CustomerID = custID;
ca.AmountRequested = amount;
ca.CreditScore1 = score1;
ca.CreditScore2 = score2;

   //populate context info to be used for logging; note "policy version" is actually set within the ruleset for easier updates
ContextFact cf = new ContextFact();
cf.PolicyName = "Microsoft.Demo.Blog.Rules";

   //here we set the source application that calls this service for tracking
cf.SourceApplication = callingApp;
cf.TimeStampValue = DateTime.Now;

   //set up rules policy to fire off using the basic Policy object; note that I could call a specific rule version here as well
Policy p = new Policy("Microsoft.Demo.Blog.Rules");
object[] facts = new object[2];
facts[0] = ca;
facts[1] = cf;

   //execute policy passing in 2 facts

   //return boolean value modified by the rules engine
return ca.ApprovalStatus;

So, when I execute this rule, I log all the info to an XML file now. Instead of just reading the execution results as XML, I added a simple little XSLT to my XML log so that I could have an attractive front end.

Voila. Now every time a rule policy gets executed, I know who called it, and which rules fired.

Obviously you could add all sorts of context information about the rule execution cycle and easily be able to go back in time and see what fired when, and by whom. The key takeaway is that you can execute any GAC’ed .NET assembly from a rule, so you could theoretically do all kinds of interesting activities from a rule, like logging or notification.

If you're interested in the source code, lemme know.