CodeFluent Entities Documentation
Rule methods
See Also Send comments on this topic.
CodeFluent Entities > Reference Guide > CodeFluent Query Language (CFQL) > Rule methods

Glossary Item Box

CodeFluent proposes a mechanism to implement custom external business rules:

  1. The rule signature is defined with the entity, using CFQL.
  2. The rule body is not defined in the model (or maybe only its default implementation), because by definition, it may vary over time independently from the model, more probably sticking to evolving business needs. CodeFluent proposes two rule engine implementations out-of-the-box today.

This allows to create various types of custom business rules, from a simple syntax validation check, to a sophisticated business processing rule.

Although it is perfectly feasible, and easy to implement, to directly write custom code using .NET inheritance mechanism or partial classes,  the benefits of defining rules in the model is to have all producers create their target artifacts automatically, regardless of where and how the rule is actually implemented. For example, the Web Service producer will by default automatically create one Service operation for each rule defined in the model. It is therefore quite easy to implement an SOA (Service Oriented Architecture) on top of CodeFluent generated artifacts.

More information such as available operators, examples or advanced methods, can be found in the Architect Guide, and more especially in the Methods chapter.

Reason to use a Rule method

The Rule method mechanism must not be used in every custom business rule scenario. Here are some reasons why you would want to define Rule methods:

  1. The rule lifecycle is different than your application lifecycle. For example, the rule must follow legal constraint that vary independently from your application major releases.
  2. The rule implementation may be done in another language or technology. For example, your application is programmed using CSharp, and the rule may be programmed using VB.NET.
  3. The rule developers are not part of the application team. For example, you want to outsource the development of the rule.
  4. The rule is implemented using a standard Rule engine (such as Ilog Rules for .NET, or Microsoft BizTalk BRE, or Windows Workflow Foundation)

Rule definition

Rule definition is done using CFQL. CFQL only supports the definition of arguments and arguments types, not the body. The syntax is:

rule([argumentType1] argument1, [argumentType2] argument2, ... , [argumentTypeN] argumentN)

Argument types are parsed using CodeFluent type system algorithms. Each argument definition can be completed by argument XML method elements.

Return type is defined in the method XML element.

Rule implementation

Unlike load methods, CFQL does not allow direct rule body definition and rule implementation is external to the model.

The Business Object Model Producer implements the rule signature as a regular CLR method on the entity. The implementation of this method simply defers the call to a rule engine class that must either implement the generic CodeFluent.Runtime.Rules.IMethod interface or a public method which is signature-compatible with the modeled rule method.

Two standard rule engines class are provided today:

The script rule engine is the default rule engine if the typeName attribute is not defined on the method XML element.

Example 1: using Script rule engine

Here, the rule body is implemented in JavaScript. The RuleBody parameter, specific to the Script Rule engine, defines the initial rule body. Once run, the rule body is saved as a .js file under the application base directory and can be changed using a text editor.

XML Copy Code
<Customer>
 ...
 <cf:method name="RebateCompute" body="rule(Category)">
  <cf:setting name="RuleBody"><![CDATA[
   if (Category.Name == 'Birds') { Customer.Rebate = 20;}
   &cd;>
  </cf:setting>
 </cf:method>
 ...
</Customer>

Example 2: using Ilog Rules for .NET

In this method, the rule body is implemented using Ilog Rules for .NET. A wrapper class is provided by CodeFluent that directly binds to the RuleEngine class. The RuleSetTypeName parameter, specific to this wrapper, defines the implementing assembly.

XML Copy Code
<Customer>
 ...
 <cf:method name="AgeCheck" typeName="CodeFluent.Runtime.Rules.ILog.Method, CodeFluent.Runtime.Rules.ILog"
  returnTypeName="int"
  body="rule()">
  <cf:setting name="RuleSetTypeName" value="CarRentalBizProj, CarRentalBizProj"/>
 </cf:method>
 ...
</Customer>

Example 3: using a custom IMethod rule in C#

In this method, the rule body is implemented using a custom C# class. The class must implement the IMethod and can define and document optional static settings it could use.

XML Copy Code
<Customer>
    ...
    <cf:method name="ValidateOffer" typeName="Test.MyRule, MyProject.MyRules"
       body="rule(Offer)">
      <cf:setting name="MyCustomSetting" value="Value"/>
    </cf:method>
    ...
</Customer>         

MyRule.cs

CSharp Copy Code
public class MyRule: IMethod
{
  public MyRule() {} // we need a public parameterless constructor
  
  public object Invoke(IDictionary settings, IDictionary arguments) // the unique IMethod method
  {
    if (settings == null)
      throw new ApplicationException("missingRuleSetTypeNameSetting");
      
    string myCustomSetting = ConvertUtilities.Nullify(settings["MyCustomSetting"] as string, true);
    if (ruleSetTypeName == null)
      throw new ApplicationException("missingRuleSetTypeNameSetting");
    
    Customer customer = (Customer)arguments["Customer"];   // there is always the "this" argument passed using entity type name
    Offer offer = (Offer)arguments["Offer"];               // this was defined as a rule argument
    
    // TODO: do the work here.
    
    return null; // Note: no need to return anything because returnTypeName is not defined on the method XML element
  }
}

Example 4: using a custom typed signature-compatible rule in C#

In this method, the rule body is implemented using a custom C# class. The class must implement the IMethod and can define and document optional static settings it could use.

XML Copy Code
<Customer>
    ...
    <cf:method name="ValidateOffer" typeName="Test.MyRule, MyProject.MyRules"
       body="rule(Offer)">
      <cf:setting name="MyCustomSetting" value="Value"/>
    </cf:method>
    ...
</Customer>         

MyRule.cs

CSharp Copy Code
public class MyRule
{
  public MyRule() {} // we need a public parameterless constructor
  
  public void ValidateOffer(Customer customer, Offer offer) // this is a signature compatible public instance method
  {
    // TODO: do the work here.
  }
}

See Also