Sunday, 10 July 2016

Business Rule Engine (BRE) | BizTalk-Part 3


In this article, I would explain how to leverage BRE functionality with the XMLHelper class.

Here, we would validate an incoming XML message and generate an aggregated XML message containing all validation failures. The base functionality of the BRE does not allow this kind of message manipulation - adding new elements (nodes) to messages and then setting the value. 

BizTalk Server  supports the usage of static objects without passing that particular object into the rule as a “fact.” However, a registry change is needed to get it working.

To enable calling these methods, add a REG_DWORD key named “StaticSupport“, with a value of “1” to the following registry path: 

32-bit Windows 
HKEY_LOCAL_MACHINE\Software\Microsoft\BusinessRules\3.0\ 64-bit Windows 
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\BusinessRules\3.0\ 

BizTalk Rule Engine provide as XML Helper,refer the class files, But for our sample, I would use this class in a separate assembly which would give us control to modify the method to our requirement. I updated the BRE XML helper with the below property functions, constructor and a static method. 

Modified Utility 
public string statusCode { get; set; } 
public string statusDesc { get; set; } 
public bool isRuleFired { get; set; } 
public bool haltRuleExection { get; set; } 
public string executionOutCome { get; set; } 

public Utility() 

  statusCode = string.Empty; 
  statusDesc = string.Empty; 
  isRuleFired = false; 
  haltRuleExection = false; 
  executionOutCome = string.Empty; 


public static string NodeCount(TypedXmlDocument document, string xpath) 

  int count = document.Document.SelectNodes(xpath, document.NamespaceManager).Count; 
  return count.ToString(); 


public static void AddAttribute(TypedXmlDocument document, string xpath, string attributeName, object attributeValue)
        {
            if (document == null)
                throw new ArgumentNullException("document");
            if (string.IsNullOrEmpty(xpath))
                throw new ArgumentNullException("xpath");
            if (string.IsNullOrEmpty(attributeName))
                throw new ArgumentNullException("attributeName");
            if (attributeValue == null)
                throw new ArgumentNullException("attributeValue");
            XmlElement xmlElement = LocateXPath(document, xpath) as XmlElement;
            if (xmlElement == null)
                return;
            xmlElement.SetAttribute(attributeName, attributeValue.ToString());
            document.MarkAsChanged();
        }

        public static void AddNode(TypedXmlDocument document, string xpath, string nodeName, string nodeNamespace)
        {
            if (document == null)
                throw new ArgumentNullException("document");
            if (string.IsNullOrEmpty(xpath))
                throw new ArgumentNullException("xpath");
            if (string.IsNullOrEmpty(nodeName))
                throw new ArgumentNullException("nodeName");
            if (string.IsNullOrEmpty(nodeNamespace))
                throw new ArgumentNullException("nodeNamespace");
            XmlNode xmlNode = LocateXPath(document, xpath);
            if (xmlNode == null)
                return;
            XmlDocument xmlDocument = xmlNode.OwnerDocument;
            if (xmlDocument == null)
            {
                xmlDocument = document.Document as XmlDocument;
                if (xmlDocument == null)
                    return;
            }
            XmlElement element = xmlDocument.CreateElement(nodeName, nodeNamespace);
            xmlNode.InsertBefore((XmlNode)element, (XmlNode)null);
            document.MarkAsChanged();
        }

        public static void AddNode(TypedXmlDocument document, string xpath, string nodeName)
        {
            if (document == null)
                throw new ArgumentNullException("document");
            if (string.IsNullOrEmpty(xpath))
                throw new ArgumentNullException("xpath");
            if (string.IsNullOrEmpty(nodeName))
                throw new ArgumentNullException("nodeName");
            XmlNode xmlNode = LocateXPath(document, xpath);
            if (xmlNode == null)
                return;
            XmlDocument xmlDocument = xmlNode.OwnerDocument;
            if (xmlDocument == null)
            {
                xmlDocument = document.Document as XmlDocument;
                if (xmlDocument == null)
                    return;
            }

            XmlElement element = xmlDocument.CreateElement(xmlDocument.DocumentElement.Prefix, nodeName, xmlDocument.DocumentElement.NamespaceURI);
            xmlNode.InsertBefore((XmlNode)element, (XmlNode)null);
            document.MarkAsChanged();
        }
                
        public static void AddNodeWithValue(TypedXmlDocument document, string xpath, string nodeName, string nodeNamespace, object nodeValue)
        {
            if (document == null)
                throw new ArgumentNullException("document");
            if (string.IsNullOrEmpty(xpath))
                throw new ArgumentNullException("xpath");
            if (string.IsNullOrEmpty(nodeName))
                throw new ArgumentNullException("nodeName");
            if (string.IsNullOrEmpty(nodeNamespace))
                throw new ArgumentNullException("nodeNamespace");
            if (nodeValue == null)
                throw new ArgumentNullException("nodeValue");
            XmlNode xmlNode = LocateXPath(document, xpath);
            if (xmlNode == null)
                return;
            XmlDocument xmlDocument = xmlNode.OwnerDocument;
            if (xmlDocument == null)
            {
                xmlDocument = document.Document as XmlDocument;
                if (xmlDocument == null)
                    return;
            }
            XmlElement element = xmlDocument.CreateElement(xmlDocument.DocumentElement.Prefix, nodeName, xmlDocument.DocumentElement.NamespaceURI);
            element.InnerText = nodeValue.ToString();
            xmlNode.InsertBefore((XmlNode)element, (XmlNode)null);
            document.MarkAsChanged();
        }

        public static void AddNodeWithValue(TypedXmlDocument document, string xpath, string nodeName, object nodeValue)
        {
            if (document == null)
                throw new ArgumentNullException("document");
            if (string.IsNullOrEmpty(xpath))
                throw new ArgumentNullException("xpath");
            if (string.IsNullOrEmpty(nodeName))
                throw new ArgumentNullException("nodeName");
            if (nodeValue == null)
                throw new ArgumentNullException("nodeValue");
            XmlNode xmlNode = LocateXPath(document, xpath);
            if (xmlNode == null)
                return;
            XmlDocument xmlDocument = xmlNode.OwnerDocument;
            if (xmlDocument == null)
            {
                xmlDocument = document.Document as XmlDocument;
                if (xmlDocument == null)
                    return;
            }
            XmlElement element = xmlDocument.CreateElement(xmlDocument.DocumentElement.Prefix, nodeName, xmlDocument.DocumentElement.NamespaceURI);
            element.InnerText = nodeValue.ToString();
            xmlNode.InsertBefore((XmlNode)element, (XmlNode)null);
            document.MarkAsChanged();
        }

        public static void AddNodeIfNotThere(TypedXmlDocument document, string xpath, string nodeName, string nodeNamespace)
        {
            if (document == null)
                throw new ArgumentNullException("document");
            if (string.IsNullOrEmpty(xpath))
                throw new ArgumentNullException("xpath");
            if (string.IsNullOrEmpty(nodeName))
                throw new ArgumentNullException("nodeName");
            if (string.IsNullOrEmpty(nodeNamespace))
                throw new ArgumentNullException("nodeNamespace");
            XmlNode xmlNode1 = LocateXPath(document, xpath);
            if (xmlNode1 == null)
                return;
            foreach (XmlNode xmlNode2 in xmlNode1.ChildNodes)
            {
                if (xmlNode2.LocalName == nodeName && xmlNode2.NamespaceURI == nodeNamespace)
                    return;
            }
            XmlDocument xmlDocument = xmlNode1.OwnerDocument;
            if (xmlDocument == null)
            {
                xmlDocument = document.Document as XmlDocument;
                if (xmlDocument == null)
                    return;
            }
            XmlElement element = xmlDocument.CreateElement(nodeName, nodeNamespace);
            xmlNode1.InsertBefore((XmlNode)element, (XmlNode)null);
            document.MarkAsChanged();
        }

        public static void AddNodeIfNotThere(TypedXmlDocument document, string xpath, string nodeName)
        {
            if (document == null)
                throw new ArgumentNullException("document");
            if (string.IsNullOrEmpty(xpath))
                throw new ArgumentNullException("xpath");
            if (string.IsNullOrEmpty(nodeName))
                throw new ArgumentNullException("nodeName");
            XmlNode xmlNode1 = LocateXPath(document, xpath);
            if (xmlNode1 == null)
                return;
            foreach (XmlNode xmlNode2 in xmlNode1.ChildNodes)
            {
                if (xmlNode2.LocalName == nodeName)
                    return;
            }
            XmlDocument xmlDocument = xmlNode1.OwnerDocument;
            if (xmlDocument == null)
            {
                xmlDocument = document.Document as XmlDocument;
                if (xmlDocument == null)
                    return;
            }
            XmlElement element = xmlDocument.CreateElement(nodeName);
            xmlNode1.InsertBefore((XmlNode)element, (XmlNode)null);
            document.MarkAsChanged();
        }

        internal static XmlNode LocateXPath(TypedXmlDocument document, string xpath)
        {
            XmlNode document1 = document.Document;
            if (document1 == null)
                return (XmlNode)null;
            if (string.IsNullOrEmpty(xpath))
                return document1;
            else
                return document1.SelectSingleNode(xpath, document.NamespaceManager);

        }

Let’s create simple rules that validates in Order Request and add the failure reasons under validation container, 
  • Rule1: Validate Event Code, if the event isn’t any one of these events (100, 101, and 1001) then add status element with error code and error description
  • Rule2: Validate Product Name, if the event isn’t any one of these products (Title, Escrow, and Signing) then add status element with error code and error description.
  • Rule3: Validate if there are any failure, if so update the helper class with failure count. In Fact Explorer, browse and choose the BRE helper utility. 
Build the ValidateEventCode rule as shown below, similarly develop rule to validate product name.
Note:- Drag and drop the xml document from the XML Schemas in facts explorer window to TypedXmlDocument Parameters in the utility method. 
Add a rule to evaluate validation, as shown below. 

Publish and deploy the rule. In order to test the rule, we need to create fact helper as .net facts have to be generated at runtime. Create a Fact Generator as below and gac it as shown below
Now, load the XML Document fact and .Net Class fact and test the policy. 
Test Results 

Conclusion 
In this article, I covered how to develop BRE policies with the .net helper class. Now you can apply this solution to your own business scenario.

The video demonstration is available on the Youtube, here is the embedded video.


No comments:

Post a Comment

Note: only a member of this blog may post a comment.