Creating and Deploying a Policy with the Business Rules Composer
Here, you'll continue working with the same business rule used in the previous discussions. Without knowing anything about the business domain, by simply reading the rule in plain English, it is evident that you're dealing with a customer and purchase domain.
Both of these entities are fundamental for composing the business rule and for BRE execution, because the rule must first determine if the customer is a preferred member, and if so, apply a 10 percent discount to the purchase order.
Figure 9 shows a model of the Customer and PurchaseOrder entities. You can see the code for each entity in Listing 1 and Listing 2. Recall that the BRE can work with XML, a database or .NET objects; this case models the domain by using C# classes. The article code simply uses those same objects when working with the BRE.
|Figure 9. The Customer and Purchase Orders: These business entities are used to model the business domain.|
The downloadable sample code for this article contains three projects:
- Acme.RetailOperations: Represents the application or process layer of a sample application.
- Acme.BusinessEntities: Contains the Customer and PurchaseOrder entities previously discussed.
- Acme.RetailOperations.Tests: Contains unit tests that let you emergently build the application layer.
After downloading the solution, make a copy of the MSBRESample.zip
file, unzip it, open the MSBRESample.sln
file, and delete the contents of the PurchaseService.cs
files in the Acme.RetailOperations
project. Although there isn't much code to write, I want to show you how powerful Test-Driven-Development coupled with the Microsoft Business Rules Engine can benot only in decoupling the business rules from your application layer, but also in writing just enough code to get the job done. I have also provided all code listings, so you should also be able to follow along without firing up Visual Studio.
First, here's a test method to exercise the application to ensure it correctly adheres to the 10 percent discount rule for customers with a preferred membership status. The following test method is called ExecuteCustomerCheckOutDiscountAmountShouldBeTenPercent. The name tells you two things: that it's exercising the CustomerCheckOut method on the PurchaseService, and that the DiscountAmount property on the customer instance is 10 percent as shown in Listing 3 which contains the unit test code.
Of course, when you try to compile the Acme.RetailOperations.Tests project, you'll get a bunch of compilation errors because the CustomerCheckOut method doesn't exist yet.
Open the empty PurchaseService class and write enough code to at least get the unit test to compile. Listing 4 shows a very primitive CustomerCheckout method implementation. Remember, the goal at this point is to write just enough code to compile the unit test as shown below:
public class PurchaseService
public void CustomerCheckout(Customer customer)
// some logic
At this point, the unit test compiles, but will fail if you run it, because the unit test sets up the Customer
and PurchaseOrder DiscountPercentage
percent. Despite the PreferredMember
property being set to true, there is no business rule or policy that acts on this fact (the body of the CustomerCheckout
method is empty), so, as expected, the test fails (see Figure 10
Figure 10. Failed Unit Test: The unit test fails because the Microsoft BRE policy has not yet been integrated into the application layer.
Figure 11. Business Rules Composer: Start the Business Rules Composer from the Microsoft BizTalk Server 2006 program group.
The goal now is to write enough code to get the test to pass, so you need to enforce the business rule, and you'll use the Microsoft BRE to do just that.
Start the Business Rules Composer by going to Start → Program → Microsoft BizTalk Server 2006 → Business Rule Composer as shown in Figure 11. In the upper left-hand corner, you'll find the Policy Explorer. Right-click the Policy root and click "Add New Policy" as shown in Figure 12. Provide a name for the policy that is intuitive and representative of the business domain, such as "Customer Discounts Policy." As shown in Figure 13, notice that the new Policy is automatically versioned to 1.0. Right-click the version, select "Add New Rule," and name the rule "Preferred Member Customer Discount."
Figure 12. New Policy: Adding a new policy lets you group business roles according to domain-specific groups.
Figure 13. Fixed Policies: After creating a new policy, it is versioned and cannot be changed after deployment to the repository.
On the right pane is a surface area on which to build your condition. As you might imagine, this is simply an If statement with some predicates. Select the Equal predicate as shown in Figure 14. You will use this equality predicate to determine if the customer is a preferred member.
Figure 14. Predicates: The equality predicate is just one of several predicates for building conditional business rules within the Business Rules Composer.
Figure 15. Global Assembly Cache: You must add assemblies containing assertable facts to the GAC.
To use the predicate, you need to tell the BRE which fact slot will contain the data that determines whether the customer is a preferred member, so under Fact Explorer, click the .NET Class tab, right-click ".NET Assemblies" and then click Browse. As shown in Figure 15, a list of assemblies appears. The list is an enumeration of the assemblies in the Global Assembly Cache (GAC), which is a requirement for .NET objects that will be used as facts (if you have not already done so, add the Acme.BusinessEntities.dll assembly to the GAC prior to browsing for it). Select the Acme.BusinessEntities.dll and click OK.
Figure 16. Facts and Fact Slots: Facts consist of fact slots, which in the case of .NET types include accessors for working with the fact.
Figure 17. Equality Predicates: An equality predicate requires two arguments. You provide the first argument by dragging and dropping the pertinent fact slot from the Customer fact.
Both Customer and PurchaseOrder classes are enumerated under the ".NET Assemblies" root. If you expand the Customer class, you will find accessors for all public properties, including the PreferredMember property (see Figure 16). Drag the PreferredMember get accessor to the Condition surface area, and drop it onto "Argument 1." The condition should now look like Figure 17. Now, click “Argument 2” and type “true” without the quotes as shown in Figure 18. You now have a full condition that inspects the PreferredMember fact slot on the Customer fact and tests the value for equality to true. Recall that a condition will always result in a Boolean value.
Figure 18. Conditions: A condition is simply an If/Then statement that always results in a Boolean true or false.
Figure 19. Completed Rule: A business rule is the combination of the condition and the action to take when the condition evaluates to true.
With the condition complete, all that's left is to provide the BRE with an action to execute when the condition is true. In this case, you simply want to set the DiscountPercentage property on the PurchaseOrder fact to 10 percent. Drag the DiscountPercentage set accessor from the PurchaseOrder fact and drop it on the Actions design surface. Figure 19 shows the compete rule with conditions and corresponding action that should fire if the condition evaluates to true.
Note that creating vocabulary definitions is useful for creating friendly names to apply to otherwise esoteric facts and fact slots. For example, if you are using an XML message as a fact and have a complex XPath query to map a condition argument to a fact slot, you may quickly defeat the purpose of exposing your rules in a way that supports inter-role collaboration. The solution to this dilemma is to create vocabulary definitions that act as aliases for fact slots that would otherwise be unreadable to the non-developer (even I detest reading XPath statements!). However, because this example uses .NET types modeled after the business domain, I have skipped creating vocabulary definitions altogether here.
At this point, you have successfully created the "Preferred Member Customer Discount" rule within the "Customer Discounts Policy" policy. Right-click the policy and save the rule.