![]() |
Enterprise Systems »
Microsoft BizTalk Server »
General
Intermediate
License: The Code Project Open License (CPOL)
Developing with the Microsoft Business Rule EngineBy mohamad halabiExplains practically working and developing with the Business Rule Engine (BRE). |
C#, .NET, Architect, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
This article is for two sets of readers: those who are new to Microsoft Business Rule Engine and are looking for a direct hands-on approach rather than going though the theory and architecture behind BRE (links for that at the Additional Resources section), and those who are familiar (but not experts) with the topic in general, and are looking to understand, in a practical manner, how to program with BRE and leverage some of its powerful offerings.
All applications include business rules (at least they should). Modeling these business rules inside the application code directly adds several maintenance and operation challenges:
Before getting you jumping of excitement, there is one huge problem currently in BRE: it is only available as a part of a BizTalk Server License. This means that in order to use it, you have to purchase BizTalk Server; not so nice I know. There are talks that Microsoft will make BRE a standalone product, but if that’s true or of it will happen anytime soon remains unclear.
So for the time being, you will most probably utilize BRE only in solutions which already has a BizTalk Server license as part of it.
Before delving into the topic, please take into account that while I intend to present the most of practical BRE development, there are a lot of details regarding its architecture and API which are not covered here. The Additional Resources section at the end of the article presents MSDN links that cover BRE.
To start with, the inner workings of BRE are based on the RETE algorithm; a highly efficient algorithm for implementing business rule engines. This article won’t touch on the topic, but if you are interested about how BRE is working internally, you should read the link shown on the Additional Resources section.
So, let’s start with some definitions in simple terms:
To install BRE, run the BizTalk Server installation wizard. Uncheck all options except for the Business Rules Components option, as shown in the figure below:
First, let’s create the .NET business data model. It’s the data that we are going to create our business rules against.
Create a C# class library called “BusinessModel”. Now, create a class “Applicant” as follows:
namespace BusinessModel
{
public class Applicant
{
int applicantAge;
public int ApplicantAge
{
get { return applicantAge; }
set { applicantAge = value; }
}
int projectLoanAmount;
public int ProjectLoanAmount
{
get { return projectLoanAmount; }
set { projectLoanAmount = value; }
}
int score;
public int Score
{
get { return score; }
set { score = value; }
}
string riskGrade;
public string RiskGrade
{
get { return riskGrade; }
set { riskGrade = value; }
}
string loanRisk;
public string LoanRisk
{
get { return loanRisk; }
set { loanRisk = value; }
}
int income;
public int Income
{
get { return income; }
set { income = value; }
}
bool isApproved = false;
public bool IsApproved
{
get { return isApproved; }
set { isApproved = value; }
}
}
}
The idea here is that in our sample program later, we will populate this business object with some data, pass it into the BRE, execute a policy, and take the result back without writing a single business rule inside our code. Hold on for that though, more fun stuff ahead to get the most of the topic.
Testing is a fundamental part of any development process; the BRE is no exception. This is especially important because in BRE, a policy can be called from an application only if it’s deployed. And since a deployed policy cannot be edited anymore, there is a necessity to make sure that the deployed policy is tested thoroughly. Later, we will create the policy and pass in the fact data (our “Applicant” business model). Thinking ahead, we need a way to test this before we actually deploy the policy and run our program. Testing BRE policies can be done in two methods:
PolicyTester classThis article uses the second approach for a single reason: examining the Output Trace. This will be clear later. So now, use the below code to create a class called “ApplicantFactCreator”:
namespace BusinessModel
{
public class ApplicantFactCreator : IFactCreator
{
public object[] CreateFacts(RuleSetInfo ruleSetInfo)
{
object[] facts = new object[1];
Applicant applicant = new Applicant();
applicant.ApplicantAge = 20;
applicant.ProjectLoanAmount = 10000;
applicant.Score = 150;
applicant.Income = 10000;
facts[0] = applicant;
return facts;
}
public Type[] GetFactTypes(RuleSetInfo ruleSetInfo)
{
//not implemented
return null;
}
}
}
The class implements the IFactCreator interface which makes it available for the Business Rule Composer testing wizard. The code is simple; it mainly creates the business object (the applicant), populates it with some data, and then returns that object. Now, the object (fact instance) will be available for testing, as will be demonstrated later.
The library has to be deployed into the GAC to be used by the BRE. Sign and build the library, then use the GacUtil command to deploy the DLL into the GAC.
Open the Business Rule Composer as shown below:
You will now get the UI which we will examine as we go on. One thing to note initially is that you can select the server (database) to which the composer is connecting. The database name is “BizTalkRuleEngineDb”. The window shown below allows you to specify the database server name:
If you do not get the window at startup, you can do so by using the “Load…” option from the Rule Store menu.
Since the approach of the article is practical, let’s start creating the policies and we will explain the concepts as we go.
Create a new policy called “PriorityPolicy”. Automatically, you will get version 1 of this policy. Now, inside the version, we need to start creating rules. So, let’s roll:
Right click the version node and select “Add New Rule”. Keep the name of the created rule as “Rule1” for simplicity. Now that you have the rule, you need to start adding conditions and actions; however, you need your fact data for this. So, go to the Fact Explorer window, select the .NET classes tab, right click, and import the DLL from the GAC. Once you do so, you will see the classes we have created. Note that each property we created is represented by get and set accessors:
Now, go to the “IF” window, right click and select “Predicates GreaterThan”. In the resulting expression, drag the “get_Income” fact data into the argument1 placeholder and type “5000” into the argument2 placeholder. In the “THEN” window, drag the set_RiskGrade fact data into the “Actions” node. Type “RG2” into the set accessor. The final rule is shown below:
Just like that, you have defined your first business rule; you are saying that if the Income is greater than 5000, then set the RiskGrade to “RG2”.
Now, create a new rule – Rule2 – which sets the RiskGrade to “RG1” if Score is less than 200, as follows:
Now, if you have done some critical thinking about what we have done so far, you should notice one important hint: the order at which rules will execute will actually change the final outcome.
If both Rules 1 and 2 will be evaluated to true, then RiskGrade will be set to RG1 or RG2 depending on which rule gets executed first. To solve such cases, you should always give your rules priorities.
Without priorities or with equal priorities, rules will be executed in a random order. Priorities are set by selecting each rule and setting its priority property in the Properties window. Higher priorities get executed first. In our current example, assume that we want Rule2 to execute first and Rule1 to come second. As such, give Rule2 priority 2 and Rule1 priority 1 using the Properties window.
Now, everything we have done so far will come together. First, save your policy by right clicking on the version node and selecting Save. Recall that this will still allow you to edit your policy. Now, right click again on the version node and select “Test Policy…”. From the window opened, we now need to select the Fact Creator which we will use for testing. Recall that previously, we have created a class called ApplicantFactCreator which implements “IFactCreator”. This class creates a fact (applicant) for the sole purpose of being used for testing by the composer. Also, recall that we have deployed the DLL (which contains the fact and the fact creator) into the GAC. Now, in the fact creator portion of the window, select the “Add…” button and select the DLL from the GAC; the fact creator will be detected (since it implements IFactCreator) and listed, select it. The final view will be as follows:
Finally, click “Test”. Before examining the output trace in the next section, let’s summarize where we are:
We are building an application which processes loan requests from applicants. Based on certain rules, we want to either accept or reject that loan request. While we’re on it, we want to calculate the risk grade. By using the BRE, we are escalating processing and evaluation of our business rules.
We have created our business object which represents the applicant. For testing our rules, we have also created a fact creator class whose sole purpose is to allow us to test our rules against a true applicant (fact instance) directly from the composer UI. This is important because if we deploy the policy and test it directly in our program, we won’t be able to edit it again. Next, we installed the business object DLL in the GAC because it needs to be consumed by the BRE.
We have created our first policy which contains two rules to calculate the risk grade. We need to specify the priorities of these rules because the order in which they execute will affect the outcome of the risk grade. We have chosen to say that we want Rule2 to be evaluated first.
From the composer, we loaded our fact creator and tested our policy against it. In the next section, we will examine the output trace which will make you understand more about the BRE.
The output trace below has been reformatted for displaying purposes; also, I have deleted the GUIDs that you will see in your output screen if you have been following the steps of this article.
(Read row by row from left to right)
BusinessModel.Applicant) has been asserted into the engine. Recall that assertion means that the fact is now available for processing by the BRE.From step 8, we should take note that the fact we are dealing with here is called “Short Term Fact”, meaning that it is available for BRE only for the life time of the application execution. “Long Term Facts” can be used in cases where fact data seldom changes; a technique called Fact Retriever is used just for that. This article will not discuss Long Term Facts but you can find a link at the Additional Resources section.
For this section, create a new policy “CompletePolicy”. You also need to create three rules: Rule1, Rule2, and Rule3 as shown below :
You should be familiar with creating rules now, just note the usage of the “AND” logical operator for combining conditions…
Give Rule1 priority 3, Rule2 priority 2, and Rule3 priority1. Now, try to analyze how these rules are working: if the conditions of Rule1 are evaluated to true, then IsApproved is set to true. Rule2 and Rule3 are affected by the outcome of Rule1 because their conditions will only succeed if IsApproved is set to true (recall from the Applicant class that IsApproved is set by default to false). As you can see in this example, it is critical to give rules priorities because we want Rule2 and Rule3 to get executed only after Rule1 does.
Well now, save the new policy and use the same procedure you used before to test this policy via the fact creator. Now to the fun part again; let’s examine the output trace!
IsApproved should be set to true from Rule1, right? No, recall that Rule1 has been only evaluated, not executed; so IsApproved is still set to the default value false. So, what is the deal here? How do we tackle such a scenario? Keep reading…IsApproved is still false.IsApproved be set to true. You will see how we will benefit from this momentarily.So now, we have a problem in our hands: we want Rule2 and Rule3 to “feel” the change of IsApproved caused by Rule1; however, by the time Rule1 is executed, Rule2 and Rule3 are already evaluated to false and consequently not added to the execution agenda.
The solution is easy: recall the “Update” function we defined previously. The Update function takes a fact as a parameter and causes all rules that use this fact to be re-evaluated. So, if we edit Rule1 action to include the update statement, this should solve the problem as follows:
Now, run the test again. Oops! Did you get an “out of memory exception”? That’s normal because if you carefully examine what’s going on now, you will conclude the following: after all the evaluation happens again, Rule1 will be the only one added to the agenda. So, it’s executed, and this time calls the “update” statement on the Applicant fact. As explained previously, this will retrigger the evaluation cycle again and causes the Applicant fact to be asserted with the updated IsApproved property set to true. Cool so far. So now, on the next evaluation cycle, all rules including 2 and 3 will be evaluated to true (because IsApproved is set to true), and as a result, the agenda will include Rules 1, 2, and 3. Next, Rule1 is executed. Can you guess what happens then? The update statement is executed again causing re-assertion and re-evaluation without Rules 2 and 3 being fired at all. Think about this and you will conclude that you got yourself a nice infinite loop going on! That’s why you are receiving the out of memory exception.
By the way, just in case you are tempted to think that you can solve this problem by adjusting priorities so that Rules 2 or 3 would fire first, think again. Setting aside the fact that this would basically damage your business rules, even if Rule3 is executed last, the update statement would still cause the re-assertion and re-evaluation to occur each and every time Rule1 is executed. So, in short, priorities have nothing to do with solving such problems.
The solution actually is simple, and it is a common programming sense: just code against it! The following figure shows Rule1 modified to solve the infinite loop problem:
You just have to add a condition to ensure that Rule1 does not get executed if IsApproved has been already set to true.
Now, go on to test the policy. Since by now you should be familiar with interpreting the output trace, I won’t list it here. But, its summary here is what is going on:
IsApproved is set to true. The update function causes the Applicant fact to be re-asserted and all rules to be evaluated again (because they are using the Applicant fact, they would not be re-evaluated otherwise).IsApproved is set to true. However, Rule1 does not pass the evaluation this time because we have added a condition of testing IsApproved against being true. Rule3 fails the evaluation because of the score condition.Just kidding…calling policies from .NET is just that: you declare the policy name you want to call, pass in the fact instance, and then execute. The below code shows just that:
Applicant applicant = new Applicant();
applicant.ApplicantAge = 20;
applicant.ProjectLoanAmount = 10000;
applicant.Score = 150;
applicant.Income = 10000;
Policy policy = new Policy("CompletePolicy");
policy.Execute(applicant);
Working with BRE does not differ on whether you intent to call policies from .NET or BizTalk. While this article won’t discuss it, basically you create your rules just like you did following this article. You test them the same way. Finally, when you’re ready, you place a CallRules shape inside your orchestration and configure it to call the required policy and pass in the fact source, which is usually your XML message.
| You must Sign In to use this message board. | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 5 Feb 2009 Editor: Smitha Vijayan |
Copyright 2009 by mohamad halabi Everything else Copyright © CodeProject, 1999-2009 Web21 | Advertise on the Code Project |