Validating hierarchy

From FlexRule Wiki
Jump to: navigation, search

Assumptions

In this article we discuss how an inheritance relation can be validated based on the concrete types of the objects. Assume in your application you have the following model of a hierarchy.
Contact model
And assume you are going to design a single validation rule that contains multiple of logic for your model.

  1. <Validation name="ContactRule">
  2.     ...
  3.  
  4.     <Logic name="Logic1">
  5.     ...
  6.     </Logic>
  7.  
  8.     ...
  9.  
  10.     <Logic name="Logic2">
  11.     ...
  12.     </Logic>
  13.     ...
  14.  
  15. </Validation>


Application behaviour

When you have a inheritance hierarchy in the model, during the validation your application have two options:

  1. Manual validation
  2. Automatic validation

In the manual validation application by knowing the type of the concrete type decides what logic of the validation rule needs to be invoked. In the other hand, in the automatic validation the decision of which logic to be invoked is embedded into your validation rule. The validation finds the proper logic related to your concrete type and invokes it.

Externalizing this decision to the validation rule itself can help you to extend your model hierarchy without worries of the validation and extend the rule later on to support more types.

The good news is the automatic scenario still requires the same logic as if you decide to go for the manual one. It has all the logic of the manual one plus one more logic which routes the validation execution to the proper logic.

Rules

In the article we are going to define the following rules

  1. Contact.Name, Contact.Email, For Person.Title and Company.BusinessNumber
    1. cannot be null or empty
    2. cannot start or end with space padding (if so, has to be removed)
  2. Contact.Email must match: name@domain.ext

Dividing the logic based on type

The first step is creating two logic for your concrete types, each for each type that needs to be validated

  1. <Validation name="ContactRule">
  2.   <Logic name="Person">
  3.     <Or negate="true">
  4.       <!--Check for name-->
  5.       <Null value="Name"/>
  6.       <Empty value="Name"/>
  7.  
  8.       <!--Check for email-->
  9.       <Null value="Email"/>
  10.       <Empty value="Email"/>
  11.     </Or>
  12.   </Logic>
  13.  
  14.   <Logic name="Company">
  15.     <Or negate="true">
  16.       <!--Check for name-->
  17.       <Null value="Name"/>
  18.       <Empty value="Name"/>
  19.  
  20.       <!--Check for email-->
  21.       <Null value="Email"/>
  22.       <Empty value="Email"/>
  23.  
  24.       <!--Check for business number-->
  25.       <Null value="BusinessNumber"/>
  26.       <Empty value="BusinessNumber"/>
  27.     </Or>
  28.   </Logic>
  29. </Validation>

Null, Empty commands in the validation rules checks if the provided value on the command is null or empty. And Or commands combines the results as an 'or' boolean operation. If they are null or empty then the values are not accepted. Therefore we set the negate property of Or to true. Which means it is a negative or condition.

Logic reuse and enhancement

As you can see the combination of checking for Null and Empty is keeping repeated. In order to refactor this and reuse it we can create a new logic named ValidString that checks for both not being null and nut being empty.

  1. <Logic name="ValidString" variable="str">
  2.    <Or negate="true">
  3.      <Null value="str" />
  4.      <Empty value="str" />
  5.    </Or>
  6. </Logic>

As the result the validation rule becomes like this:

  1. <Validation name="ContactRule">
  2.   <Logic name="Person">
  3.     <And>
  4.       <Validate logic="ValidString" value="Name"/>
  5.       <Validate logic="ValidString" value="Email"/>
  6.       <Regex pattern="\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" value="Email" message="Email is not valid" />
  7.     </And>
  8.   </Logic>
  9.  
  10.   <Logic name="Company">
  11.     <And>
  12.       <Validate logic="ValidString" value="Name"/>
  13.       <Validate logic="ValidString" value="Email"/>
  14.       <Validate logic="ValidString" value="BusinessNumber"/>
  15.       <Regex pattern="\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" value="Email" message="Email is not valid" />
  16.     </And>
  17.   </Logic>
  18.  
  19.   <Logic name="ValidString" variable="str">
  20.     <Or negate="true">
  21.       <Null value="str" />
  22.       <Empty value="str" />
  23.     </Or>
  24.   </Logic>
  25. </Validation>

As you have noticed you can call to a defined logic using Validate command in validation logic.

Calling manual validation

By this point the manual validation rule is now ready to be called via your application.

  1. // Loads rule engine
  2. var engine = RuleEngine.FromXml(File.OpenRead(RuleFilePath));
  3.  
  4. // Prepare your data object to be validated
  5. PersonContact contact = new PersonContact();
  6. contact.Name = "aaaa";
  7. contact.Family = "bbbb";
  8.  
  9. // now you are ready to validate the object
  10. string logicNameToCall = "Person";
  11. bool res = engine.Run(new RunParameter(logicNameToCall, contact));

As you can see in the highlighted lines, we specify the logic name to be called by using the proper overload of the Run method.

Automating validation for concrete type

Now the only part is missing is the logic that routes the validation of Contact to its corresponding concrete types. We will be adding a logic like

  1. <Logic name="Contact">
  2.   <Or>
  3.     <!-- 
  4.          adding multiple 'validate' commands here for all concrete types.
  5.          If any of the concrete types passes then we do not need to continue processing the rest.
  6.      -->
  7.   </Or>
  8. </Logic>

In order to make this happen you can use When commands inside a Validate.

  1. <Logic name="Contact">
  2.   <Or>
  3.     <Validate logic="ValidatePersonContact">
  4.       <When>
  5.         <And>
  6.           <Contains value="Family"/>
  7.           <Contains value="Title"/>
  8.         </And>
  9.       </When>
  10.     </Validate>
  11.     <Validate logic="ValidateCompanyContact">
  12.       <When>
  13.         <And>
  14.           <Contains value="BusinessNumber"/>
  15.         </And>
  16.       </When>
  17.     </Validate>
  18.   </Or>
  19. </Logic>

In this example or used Contains command to decided which type is which. The logic distinguish different Contracts by their available properties here.

Final rule

The resulting rule looks like the following definition:

  1. <Validation name="ContactRule">
  2.   <Logic name="Contact">
  3.     <Or>
  4.       <Validate logic="ValidatePersonContact">
  5.         <When>
  6.           <And>
  7.             <Contains value="Family"/>
  8.             <Contains value="Title"/>
  9.           </And>
  10.         </When>
  11.       </Validate>
  12.       <Validate logic="ValidateCompanyContact">
  13.         <When>
  14.           <And>
  15.             <Contains value="BusinessNumber"/>
  16.           </And>
  17.         </When>
  18.       </Validate>
  19.     </Or>
  20.   </Logic>
  21.  
  22.   <Logic name="Person">
  23.     <Or negate="true">
  24.       <Validate logic="ValidString" value="Name"/>
  25.       <Validate logic="ValidString" value="Email"/>
  26.     </Or>
  27.   </Logic>
  28.  
  29.   <Logic name="Company">
  30.     <Or negate="true">
  31.       <Validate logic="ValidString" value="Name"/>
  32.       <Validate logic="ValidString" value="Email"/>
  33.       <Validate logic="ValidString" value="BusinessNumber"/>
  34.     </Or>
  35.   </Logic>
  36.  
  37.   <Logic name="ValidString" variable="str">
  38.     <And>
  39.       <Null value="str" />
  40.       <Empty value="str" />
  41.     </And>
  42.   </Logic>
  43. </Validation>

Next sections

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

  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