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 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 of your application you have two options:

  1. Manual validation
  2. Automatic validation

In the manual validation application, by knowing the type of the concrete type you can decide what logic of the validation rule needs to be invoked. On the other hand, in the automatic validation the decision of which logic is 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 worrying about the validation and also enables you to extend the rule later on to support more types.

The good news is the automatic scenario still requires the same logic as 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 this 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, it has to be removed)
  2. Contact.Email must match: name@domain.ext

Dividing the logic based on type

The first step is creating two logics for your concrete types, one 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 combine 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 repeated. In order to refactor this and reuse it, we can create a new logic named ValidString that checks both for neither being null nor empty.

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

As a 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 may have noticed, you can call to a defined logic using the Validate command in validation logic.

Calling manual validation

At this point, the manual validation rule is 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 missing is the logic that routes the validation of Contact to its corresponding concrete types. We will be adding a logic akin to:

  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 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 the Contains command to decided which type is which. The logic distinguishes different Contracts by their available properties in this case.

Final rule

The resulting rule looks similar to 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 aspects 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