BizTalk Server:Receive Pipeline Component To Validate Incoming Data

BizTalk Server:Receive Pipeline Component To Validate Incoming Data



Problem

BizTalk default EDI validation will validate data base on Schema Enumerations only, not base on some other’s node value. By using this component you can achieve conditional validation.

Solution

Validate second Node’s value base on the first Node’s Value.  Example: HIPPA 5010 834 When BGN08 = “4”, then INS03 must be “030” Or “024” Will return Error/ Warning or Information if validation failed.

Component Code

The component code has 4 blocks:

  1. IBaseComponent - To define Name, Version and Description of component.
  2. IpersistPropertyBag – To read write proprieties.
  3. IcomponentUI – Set Icon of component.
  4. Icomponent – Contain Execute() where we write code to process  incoming message.

Execute(): Code here

       
/// <summary>
      /// Implements IComponent.Execute method.
      /// </summary>
      /// <param name="pContext">Pipeline context</param>
      /// <param name="pInMsg">Input message</param>
      /// <returns>Original input message</returns>
      /// <remarks>
      /// IComponent.Execute method is used to initiate
      /// the processing of the message in this pipeline component.
      /// </remarks>
      IBaseMessage Microsoft.BizTalk.Component.Interop.IComponent.Execute(IPipelineContext pContext, IBaseMessage pInMsg)
      {
          EventLog.WriteEntry("H19", "STARTED...V2.3", System.Diagnostics.EventLogEntryType.SuccessAudit);
 
          bool IsValidVal = false;
          string outVal = string.Empty;
          string XmlData = string.Empty;
          IBaseMessagePart bodyPart = pInMsg.BodyPart;
 
          System.IO.StreamReader sr = new System.IO.StreamReader(bodyPart.Data);
          XmlData = sr.ReadToEnd();
 
          // IF EDI Ack then return as it is
          if (string.Equals(XmlData, string.Empty) || XmlData.Contains("X12_997_Root") || XmlData.Contains("X12_TA1_Root"))
              return pInMsg;
 
          EventLog.WriteEntry("H19", "SourceValues=" + this._SourceValue + ", TargetValue=" + this._TargetValue, System.Diagnostics.EventLogEntryType.SuccessAudit);
 
          IsValidVal = HimUtility.XML.IsValidateValue(XmlData, this._SourceNodeXpath, this._SourceValue, this._TargetNodeXpath, this._TargetValue, out outVal);
 
          if (!IsValidVal)
          {
              StringBuilder sb = new StringBuilder("Invalid value ");
              sb.Append(outVal);
              sb.Append(" at node ");
              sb.Append(HimUtility.XML.GetNodeFromXpath(this._TargetNodeXpath));
              sb.Append(Environment.NewLine);
              sb.Append("-----------------------------------------------------");
              sb.Append(Environment.NewLine);
              sb.Append(HimUtility.XML.GetNodeFromXpath(this._SourceNodeXpath));
              sb.Append(" value= ");
              sb.Append(this._SourceValue);
              sb.Append(" then ");
              sb.Append(HimUtility.XML.GetNodeFromXpath(this._TargetNodeXpath));
              sb.Append(" node value must be =");
              sb.Append(this._TargetValue);
 
              if (this._FailedAction == FS.Error)
              {
                  EventLog.WriteEntry("H19", "Data Validation Failed!!", System.Diagnostics.EventLogEntryType.Error);
                  Exception Inner = new Exception(sb.ToString());
                  Exception ex = new Exception("Data Validation Failed!!", Inner);
                  ex.Source = this.Name;
 
                  throw ex;
              }
              else if (this._FailedAction == FS.Warring)
              {
                  EventLog.WriteEntry("H19", "Data Validation Failed!!" + Environment.NewLine + sb.ToString(), System.Diagnostics.EventLogEntryType.Warning);
              }
              else
              {
                  EventLog.WriteEntry("H19", "Data Validation Failed!!" + Environment.NewLine + sb.ToString(), System.Diagnostics.EventLogEntryType.Information);
              }
          }
          //Return message
          System.IO.MemoryStream strm = new System.IO.MemoryStream(ASCIIEncoding.Default.GetBytes(XmlData));
          strm.Position = 0;
          bodyPart.Data = strm;
          pContext.ResourceTracker.AddResource(strm);
 
          return pInMsg;
      }

Utility Function:  

namespace HimUtility
{
    public class XML
    {
 
        /// <summary>
        ///  Validate Second nodes value base on first node values
        /// </summary>
        /// <param name="XmlData">Inner/Outer XML data as string</param>
        /// <param name="SrcXpath">Xpath of First node</param>
        /// <param name="SrcVal">Colun (;) seperated value of First node</param>
        /// <param name="TrgXpath">Xpath of Second node</param>
        /// <param name="TrgVal">Colun (;) seperated value of Second node</param>
        /// <param name="outVal">Out parameter, return the failed seconf node value</param>
        /// <returns></returns>
        public static bool IsValidateValue(string XmlData, string SrcXpath, string SrcVal, string TrgXpath, string TrgVal, out string outVal)
        {
            bool IsValid = false;
            outVal = string.Empty;
 
            XmlDocument Xdoc = new XmlDocument();
            Xdoc.LoadXml(XmlData);
            XPathNavigator nav = Xdoc.CreateNavigator();
            XPathNodeIterator NodeIter;
 
            //Getting First node Values
            string[] FN = SrcVal.ToUpper().Split(';');
            Hashtable htSrvVal = new Hashtable();
            foreach (string s in FN)
                htSrvVal.Add(s, s);
 
 
            //Getting Second Nodes Values
            string[] SN = TrgVal.ToUpper().Split(';');
            Hashtable htTrgVal = new Hashtable();
            foreach (string s in SN)
                htTrgVal.Add(s, s);
 
            //Get XML Value of xmlVal
            XPathExpression expr;
            expr = nav.Compile(SrcXpath); // Compile a standard XPath expression
            string xmlVal = nav.SelectSingleNode(expr).InnerXml.ToUpper();
 
            // If 1st value is true then check corresponding valid values
            if (htSrvVal.ContainsKey(xmlVal))
            {
                NodeIter = nav.Select(TrgXpath);
                while (NodeIter.MoveNext())
                {
                    outVal = NodeIter.Current.Value.ToUpper();
                    IsValid = htTrgVal.ContainsKey(outVal);
                    if (!IsValid)
                        return false;
                    Console.WriteLine("TrgVal Title: {0} IsValid: {1}", NodeIter.Current.Value, IsValid);
                }
            }
            else
            {
                return true;
            }
 
            return IsValid;
 
        }
 
        /// <summary>
        /// Get node name from Xpath expression
        /// </summary>
        /// <param name="SrcXpath"></param>
        /// <returns></returns>
        public static string GetNodeFromXpath(string SrcXpath)
        {
            string NodeName = string.Empty;
 
            char[] c = { (char)39 };
            string[] tmp = SrcXpath.Split(c);
            if (tmp.Length > 4)
                NodeName = tmp[tmp.Length - 4];//True for EDI Schems
            else
                NodeName = tmp[tmp.Length];//For normal Schems's Xpath
            return NodeName;
        }
    }
}

Using the component

To use component in any receive pipeline Setup following Values a

FailedAction : What to do If validation failed, eg. Error out, Log warring or Information.
SourceNodeXpath : Instance Xpath of First Node.
SourceValue : Values the to trigger the validation check. Can give multipul vale seperated by colun (;) eg: 4
TargetNodeXpath : Instance Xpath of Second Node.
TargetValue : Values the to check. Can give multipul vale seperated by colun (;) eg: 030;024

The component code has 4 blocks:

  1. IBaseComponent - To define Name, Version and Description of component.
  2. IpersistPropertyBag – To read write properties
  3. IcomponentUI – Set Icon of component.
  4. Icomponent – Contain Execute() where we write code to process  incoming message.

Getting : Instance Xpath From XSD


Registering   Component 

Build then Deploy to GAC”

On VS Command prompt
 cd “Local path of .ddl"

gacutil /i "H19_PiplelineComponent.dll"



Verify @
C:\WINDOWS\assembly\GAC_MSIL

Adding it to tool bar



Browse then select



Points of Interest

Creating Dropdown on component configuration: Just create  enum on component

 

public enum FS { Information = 1, Warring = 2, Error = 3 }

And it will shows as Dropdown on component properties

While creating this component and searching for some thing got Online Xpath testing site http://xpath.online-toolz.com/tools/xpath-editor.php

I tookd help from Biztalk pipeline component wizard (http://btsplcw.codeplex.com/releases/view/26930)


See Also

Another important place to find a huge amount of BizTalk related articles is the TechNet Wiki itself. The best entry point is BizTalk Server Resources on the TechNet Wiki.


Leave a Comment
  • Please add 8 and 3 and type the answer here:
  • Post
Wiki - Revision Comment List(Revision Comment)
Sort by: Published Date | Most Recent | Most Useful
Comments
  • Maheshkumar S Tiwari edited Revision 4. Comment: corrected typo error  

  • Maheshkumar S Tiwari edited Revision 3. Comment: Added code block and Tag

  • Maheshkumar S Tiwari edited Revision 2. Comment: Title casing,added tags, added see also and minor edit

Page 1 of 1 (3 items)
Wikis - Comment List
Sort by: Published Date | Most Recent | Most Useful
Posting comments is temporarily disabled until 10:00am PST on Saturday, December 14th. Thank you for your patience.
Comments
  • Maheshkumar S Tiwari edited Revision 2. Comment: Title casing,added tags, added see also and minor edit

  • Maheshkumar S Tiwari edited Revision 3. Comment: Added code block and Tag

  • Maheshkumar S Tiwari edited Revision 4. Comment: corrected typo error  

Page 1 of 1 (3 items)