Working with Reusable Rules in Code Effects

Code Effects component comes with a powerful feature that allows you to reuse any evaluation type rule in any other rule as if it were a simple field of System.Boolean type.

Imagine if your organization used a simple condition of Age is greater or equal to 21 in hundreds of its business rules. Obviously, if the value of 21 changes tomorrow, your organization would need to edit, test, and re-deploy all those rules with the new value. Having that condition as a reusable rule allows for much greater flexibility, because any change to that rule is instantly adapted by all other rules that may use it.

For example, consider the following source object:

using System;
using CodeEffects.Rule.Attributes;
 
namespace TestProject
{
	public class Patient
	{
		public string Name { getset; }
 
		public Gender Gender { getset; }
 
		[Field(DisplayName = "Date of Birth",
			DateTimeFormat = "MMMM dd, yyyy")]
		public DateTime? DOB { getset; }
 
		[Method("Age""Returns age of the patient")]
		public int GetAge()
		{
			if(this.DOB == nullthrow new Exception("DOB is not set");
			else return DateTime.Now.Year - ((DateTime)this.DOB).Year;
		}
 
		// C-tor
		public Patient()
		{
			this.Gender = Site.Gender.Unknown;
		}
	}
 
	public enum Gender
	{
		Male,
		Female,
		[ExcludeFromEvaluation]
		Unknown
	}
}

If we were to register Code Effects component on a web page with this Patient class as a source object, we could create an evaluation type rule that checks if the patient is 21 or older, name that rule "Legal Age", and save it:

Later, we could reuse that rule in other rules as if it were a field of bool type called "Legal Age" by adding it to the collection of items in the Rules menu and fields context menu the next time we load the page (more about adding items to the Rules menu can be found in the Toolbar topic). So, the selection of this rule from the Rules menu for editing would look like this:

It would also look like an ordinary rule field in the context menu when you create other rules:

Notice that the Help String displays the description of our rule every time the mouse hovers over its name in either menu. It does so because we added that description in the very first step above. This feature is helpful if there are many items in the menu, or if multiple people work on the same project.

So, now we can reuse our Legal Age rule in any other rule that uses the same source object:

This powerful feature allows you to easily encapsulate common logic into separate rules and reuse them across your entire organization.

IMPORTANT! If used carelessly, reusable rules can lead to a nasty thing called "circular references". Imagine the following three business rules:

  • Rule # 1

    Check if Name is "John" and Rule # 3 is False
  • Rule # 2

    Check if Email contains ".com" and Rule # 1 is True
  • Rule # 3

    Check if Zip code is "12345" or Rule # 2 is True

It's easy to see the circular references in these rules. What makes it worse is the fact that rule author cannot see that by using Rule # 1 in the Rule # 2 (s)he actually creates a recursion.

Code Effects component comes equipped with excellent features that help developers to avoid recursions. For instance, it does not allow rule authors to reuse the rule inside of itself while this rule is being edited - the Rule Editor simply won't display a rule's name in the context menu even if the developer adds it to the menu's item collection. Code Effects component can also check for circular references during the rule validation. But it does this only if it's able to get the Rule XML of the referenced rule and check it for inner references of the rules that it has examined so far. You can force Code Effects to perform such a check by supplying it the GetRuleDelegate - a method that gets a rule ID and returns the rule's XML. You do that differently for each pattern.

In ASP.NET, set the value of RuleEditor.GetRuleDelegate:

protected override void OnLoad(EventArgs e)
{
	base.OnLoad(e);
 
	this.ruleControl.GetRuleDelegate = Storage.LoadRuleXml;
}

In MVC, pass a GetRuleDelegate to the RuleModel.IsValid() method:

[HttpPost]
public ActionResult Save(RuleModel ruleEditor)
{
	ruleEditor.BindSource(typeof(Patient));
 
	// Make sure that the Rule Area is not empty and the current rule is valid
	if(ruleEditor.IsEmpty() || !ruleEditor.IsValid(StorageService.LoadRuleXml))
	{
		ViewBag.Message = "The rule is empty or invalid";
		return View("Index");
	}

	// The rest of the action is omitted
}

(Both code samples were taken from our demo projects.)

In both cases Code Effects component will perform the recursion check during the rule validation, because it knows how to get the referenced rule if it finds one in the current rule. Code Effects component checks not only the initial rule but all referenced rules, rules referenced in those referenced rules, and so on. Don't supply the delegate if you are absolutely sure that the current rule does not reference any other rules.

If recursion is detected, the entire initial rule is marked invalid, and returned back to the client.

Post your support requests on Stackoverflow.com. You can also post your comments and product feedback using the form at the bottom of this page.
Comments: 0
Name (optional):
Comment (URLs are allowed and must start with http:// or https://; all tags will be encoded):
Remaining character count: