I don’t know about you but I find the best way to understand how something is working is from reading the code and then stepping through its execution, with VS’s trusty local and immediate windows. A friend of mine calls this  “developers documentation”, and whilst I certainly wouldn’t go as far as saying it’s a substitute for good docs (and by that Chris, I mean “living models”!), I always end up doing it during any maintenance code cycles (unintended consequences and all that).


 


Unfortunately the execution of a BizTalk rule policy isn’t quite as straight forward. It’s not a set of simple sequential steps that you can step through. If it was it would probably be far less useful as a rules engine – and certainly far less performant.. Instead it implements a RETE algorithm for small rulesets and some propriety one for large rules sets according to the man himself. Anyway the long and the short of this is that rules processing is done behind closed doors, which makes for a tough time in understanding what happened during the policy being executed. I’m sure a good understanding of the RETE process would help – Dummies guide to RETE anyone?


 


The Microsoft Business Rules Composer (BRC) does allow rule “testing” by implementing the Tracking Interceptor DebugTrackingInterceptor. The following is a sample output produced by the BRC for the Loans Processing policy (from the Loans Sample in the SDK. 


 


RULE ENGINE TRACE for RULESET: LoanProcessing 5/19/2005 12:46:13 PM


 


FACT ACTIVITY 5/19/2005 12:46:13 PM


Rule Engine Instance Identifier: fb330399-15f0-4dc7-9137-4463a32f580e


Ruleset Name: LoanProcessing


Operation: Assert


Object Type: DataConnection:Northwind:CustInfo


Object Instance Identifier: 782


 


FACT ACTIVITY 5/19/2005 12:46:13 PM


Rule Engine Instance Identifier: fb330399-15f0-4dc7-9137-4463a32f580e


Ruleset Name: LoanProcessing


Operation: Assert


Object Type: TypedXmlDocument:Microsoft.Samples.BizTalk.LoansProcessor.Case


Object Instance Identifier: 778


 


FACT ACTIVITY 5/19/2005 12:46:13 PM


Rule Engine Instance Identifier: fb330399-15f0-4dc7-9137-4463a32f580e


Ruleset Name: LoanProcessing


Operation: Assert


Object Type: TypedXmlDocument:Microsoft.Samples.BizTalk.LoansProcessor.Case:Root


Object Instance Identifier: 777


 


CONDITION EVALUATION TEST (MATCH) 5/19/2005 12:46:13 PM


Rule Engine Instance Identifier: fb330399-15f0-4dc7-9137-4463a32f580e


Ruleset Name: LoanProcessing


Test Expression: NOT(TypedXmlDocument:Microsoft.Samples.BizTalk.LoansProcessor.Case:Root.Income/BasicSalary > 0)


Left Operand Value: 12


Right Operand Value: 0


Test Result: False


 


CONDITION EVALUATION TEST (MATCH) 5/19/2005 12:46:13 PM


Rule Engine Instance Identifier: fb330399-15f0-4dc7-9137-4463a32f580e


Ruleset Name: LoanProcessing


Test Expression: NOT(TypedXmlDocument:Microsoft.Samples.BizTalk.LoansProcessor.Case:Root.Income/OtherIncome > 0)


Left Operand Value: 10


Right Operand Value: 0


Test Result: False


 


CONDITION EVALUATION TEST (MATCH) 5/19/2005 12:46:13 PM


Rule Engine Instance Identifier: fb330399-15f0-4dc7-9137-4463a32f580e


Ruleset Name: LoanProcessing


Test Expression: TypedXmlDocument:Microsoft.Samples.BizTalk.LoansProcessor.Case:Root.PlaceOfResidence/TimeInMonths >= 3


Left Operand Value: 15


Right Operand Value: 3


Test Result: True


[.. cut for brevity ..]


 


This implements the IRuleSetTrackingInterceptor interface which you can use to produce you own custom debugging/tracing of rule processing.


 


Most of the information is there (although I’m still troubled that the tracing of the process doesn’t allow you to examine the facts i.e., the data rows, xml docs etc), but it’s not exactly easy to see what’s happened. Understanding the match-conflict resolution-action helps considerably.


 


If you are executing your policy outside of BizTalk, or in a component consumed within BizTalk you can specify an alternative IRuleSetTrackingInterceptor. This has the advantage of allowing you to step through the rule processing if you wish, and also allows you to view fact details (through the facts you pass to the policy). The following code demonstrates how to invoke your MyInterceptorClass().


 


xmlDocument = IncomingXMLMessage.XMLCase;


typedXmlDocument = new Microsoft.RuleEngine.TypedXmlDocument(“Microsoft.Samples.BizTalk.LoansProcessor.Case”,xmlDocument);


policy = new Microsoft.RuleEngine.Policy(“LoanProcessing”);


policy.Execute(typedXmlDocument,new MyInterceptorClass());


OutgoingXMLMessage.XMLCase = xmlDocument;


policy.Dispose();


 


Once you understand the various stages to the rule engine, you soon yearn for a better way to visualise a complex processing of rules. To this end I started thinking about how I’d like to see what was happening. In the past I’ve used UML sequence diagrams to demonstrate how messages are sent between object and also object lifetime.


 


Initially , I though that each fact would “constructed” by assertion and “destructed” by retraction. The same would happen with the rules placed into and out of the Agenda. This is sort of how it would look;


 


 


The problem with this approach is that it makes a very complex picture when many facts are asserted and many rules get passed onto the agenda. In the end I settled for a “swim lanes” type approach, separating each phase (facts asserting/retracting, condition matching, adding to agenda and firing actions) in a lane and then just processing sequentially. I think it works quite well, but you can see the loans processing sample output here.


 


 


The TrackingInterceptor also outputs to XML. If anyone’s interested in a copy of the source/component you can drop me a note here.


 


After my experiences I have the following request for MS


 


Request 1: Allow the BRC to use a difference Tracking Interceptor


Request 2: Allow the Tracking Interceptor to get hold of the full facts – i.e., let me dump out the xmldoc.


Request 3: Allow the “Call Rules” shape to specify a tracking interceptor