Extending logic

From FlexRule Wiki
(Redirected from Extending validation rule)
Jump to: navigation, search

Introduction

There are some scenarios that validation conditions require to communicate back to the application or execution a custom behaviour. These situations can be categorised in to two areas:

  • Validate a custom condition
  • Take a custom action

In these scenarios you can use Alias or Check commands to extend the validation engine.

Custom condition

Sometimes in validation rules you may need to access an external resource, or for example implement a custom condition to participate in a validation chain. You can accomplish these task by simply using either Alias or Check.

Using Check

To use Check command you need to

  1. Add an input parameter to the rule
  2. Pass the defined parameter value to the rule when it is called
  3. Call Check command in the chain of the conditions

The following sample rule define an input parameter and calls the custom logic using Check

  1. <Validation name="PersonValidation">
  2.   <Declaration>
  3.     <Define name="MinAge" direction="In"/>
  4. 	<!-- Define the input parameter -->
  5.     <Define name="fin" direction="In" />
  6.   </Declaration>
  7.  
  8.   <Logic name="Logic with custom call">
  9.     <Group>
  10.       <Check value="fin.DbExists($this)"/>
  11.       <And />
  12.       <Null value="Name" negate="true"/>
  13.       <And />
  14.       <Empty value="Name" negate="true"/>
  15.       <Or />
  16.       <Null value="Family" negate="true"/>
  17.       <And />
  18.       <Empty value="Family" negate="true" />
  19.     </Group>
  20.   </Logic>
  21.  
  22. </Validation>

And the following code is the class definition to the fin parameter

  1. class PersonDbAccess
  2. {
  3.     public bool DbExists(object obj)
  4.     {
  5.         Person person = (Person) obj;
  6.         // Check if the person exists
  7.  
  8.         return false;
  9.     }
  10. }

Using Alias

Alias allows you to define custom rule command element in two ways:

  1. Point the rule command name to a method (either instance or static)
  2. Point the rule command name to a logic.

Please note in both cases, the name of custom command name is defined in 'as' attribute of Alias. If 'as' is not supplied, the Method name or Logic name will be picked by default.

Point to Logic

When a custom rule command name is defined:

  1. The Alias requires to be registered at Declaration section
  2. Custom command name can be used
  1. <Validation name="PersonValidation">
  2.   <Declaration>
  3.     <Alias logic="NotNullOrEmpty" as="IsValid1"/>
  4.   </Declaration>
  5.  
  6.   <Logic name="Validate1">
  7.     <IsValid1 value="Name" message="Name cannot be null or empty" />
  8.   </Logic>
  9.  
  10.   <Logic name="NullOrEmpty" variable="$input">
  11.       <Or>
  12.         <Null value="$input"/>
  13.         <Empty value="$input"/>
  14.       </Or>
  15.   </Logic>
  16. </Validation>
Point to Method

If you need more advanced method to participate in the validation chain and have access to evaluation context then you can use the Alias command. To use Alias you need to:

  1. Add an input parameter to the rule
  2. Define alias based on the required method
  3. Pass the defined parameter value to the rule when it is called
  4. Call your alias name in the chain of the conditions
Sample with instance method
  1. <Validation name="PersonValidation">
  2.   <Declaration>
  3.     <Define name="MinAge" direction="In"/>
  4.     <!-- Define the input parameter -->
  5.     <Define name="fin" direction="In" />
  6.     <!-- Define Alias for method DbExists named as FindPersonRecord -->
  7.     <Alias method="fin.DbExists" as="FindPersonRecord"/>
  8.   </Declaration>
  9.  
  10.   <Logic name="Logic with custom call">
  11.     <Group>
  12.       <FindPersonRecord />
  13.       <And />
  14.       <Null value="Name" negate="true"/>
  15.       <And />
  16.       <Empty value="Name" negate="true"/>
  17.       <Or />
  18.       <Null value="Family" negate="true"/>
  19.       <And />
  20.       <Empty value="Family" negate="true" />
  21.     </Group>
  22.   </Logic>
  23.  
  24. </Validation>

And now in your code you use something like the following code:

  1. class PersonDbAccess
  2. {
  3.     public bool DbExists(AliasContext context, object obj)
  4.     {
  5.         Person per = (Person)obj;
  6.         // Check the person record
  7.  
  8.         return true;
  9.     }
  10. }
Sample with static method

In the following example we point the Alias to a static method of custom type in an external assembly. Because we have not set 'as' attribute of alias, then the method name is picked by default.

  1. <Validation name="PersonValidation">
  2.   <Declaration>
  3.     <Define name="person" direction="In"/>
  4.  
  5.     <Using path="FlexRule.UnitTests.Engines.Validation.AliasTest+PersonUtility" assembly="FlexRule.UnitTests.dll" name="NewTypeName"/>
  6.     <Alias method="NewTypeName.IsNullOrWhiteSpace" />
  7.   </Declaration>
  8.  
  9.   <Logic name="person check">
  10.     <And>
  11.       <IsNullOrWhiteSpace negate="true" value="person.Name" message="Name is empty!"/>
  12.     </And>
  13.   </Logic>
  14.  
  15. </Validation>

Please note 'NewTypeName' is defined at line 5 which imports a type defined in 'path' with a new name.

Sending Information to Method

Sometimes it is required the method that implements Alias receives some more extra information. These extra information are available via AliasContext. In AliasContext your code have ability to access some settings of the alias command and take decision based on it. By using this mechanism the rule command can pass information to the method.

For example in the following code we are passing a name attribute to the method to take decision based on it.

  1. <Validation name="PersonValidation">
  2.   <Declaration>
  3.     <Define name="MinAge" direction="In"/>
  4.     <!-- Define the input parameter -->
  5.     <Define name="fin" direction="In" />
  6.     <!-- Define Alias for method DbExists named as FindPersonRecord -->
  7.     <Alias method="fin.DbExists" as="FindPersonRecord"/>
  8.   </Declaration>
  9.  
  10.   <Logic name="Logic with custom call">
  11.     <Group>
  12.       <FindPersonRecord name="5044162C-3DAA-499C-87DC-E325366B10E3" />
  13.       <And />
  14.       <Null value="Name" negate="true"/>
  15.       <And />
  16.       <Empty value="Name" negate="true"/>
  17.       <Or />
  18.       <Null value="Family" negate="true"/>
  19.       <And />
  20.       <Empty value="Family" negate="true" />
  21.     </Group>
  22.   </Logic>
  23.  
  24. </Validation>

and the method looks like the following code. It also allows you to check more detail about the Alias information by IAliasInfo interface.

  1. class PersonDbAccess
  2. {
  3.     public bool DbExists(AliasContext context, object obj)
  4.     {
  5.         // Check for the Alias information: Name, Method and Reference
  6.         var aliasInfo = context.Alias;
  7.  
  8.         // Check for the command settings
  9.         if (context.Dictionary.ContainsKey("name"))
  10.         {
  11.             string name = context.Dictionary["name"];
  12.             // Do what it is required with 'name' here
  13.         }
  14.  
  15.         Person per = (Person)obj;
  16.         // Check the person record
  17.  
  18.         return true;
  19.     }
  20. }

Custom actions

In the logic of the validation you can have Then section. If the logic condition is satisfied Then will be executed. There are two actions you may want to take in Then section:

  1. Set a variable value
  2. Call your custom action

Set variable value

To set a variable value in the rule you simply can define some output parameters and set them using Var command.

  1. <Validation name="PersonValidation">
  2.   <Declaration>
  3.     <Define name="MinAge" direction="In"/>
  4.     <!-- Define an output parameter to be set in Then section -->
  5. 	<Define name="state" direction="Out" />
  6.   </Declaration>
  7.  
  8.   <Logic name="basic validation 2">
  9.     <Group>
  10.       <Check value="Age &lt; MinAge"/>
  11.     </Group>
  12.     <Then>
  13.       <Var name="state" value="0i" />
  14.     </Then>
  15.   </Logic>
  16.  
  17. </Validation>

Call your custom action

Or you can use the Alias command in the Then section like the following rule:

  1. <Validation name="PersonValidation">
  2.   <Declaration>
  3.     <Define name="MinAge" direction="In"/>
  4.     <Define name="fin" direction="In" />
  5. 	<!-- setup alias command -->
  6.     <Alias ref="fin" method="WriteDb" as="RecordResult"/>
  7.   </Declaration>
  8.  
  9.   <Logic name="basic validation 2">
  10.     <Group>
  11.       <Check value="Age &lt; MinAge"/>
  12.     </Group>
  13.     <Then>
  14.       <RecordResult />
  15.     </Then>
  16.   </Logic>
  17.  
  18. </Validation>


And the code for this alias is something like:

  1. class PersonDbAccess
  2. {
  3.     public void WriteDb(AliasContext context, object obj)
  4.     {
  5.         Person person = (Person) obj;
  6.         // Do whatever is required for the person
  7.     }
  8. }

Next sections

In the next couple of articles we will cover different aspect of modelling and executing the validation rules using Validation engine.

  1. Introduction to validation rules
  2. Validating hierarchy (Inheritance relation)
  3. Validating association (Aggregation, Composition)
  4. Validation rule execution and collecting results
  5. Pass extra input values to validation rules
  6. Extending validation conditions and actions
  7. How to apply rules under some conditions
  8. Referencing commonly used logic
  9. Sample for Order processing validation logic