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 properties.
  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 (;) separated value of First node</param>
        /// <param name="TrgXpath">Xpath of Second node</param>
        /// <param name="TrgVal">Colun (;) separated value of Second node</param>
        /// <param name="outVal">Out parameter, return the failed second 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 separated by colun (;) eg: 4
  • TargetNodeXpath : Instance Xpath of Second Node.
  • TargetValue : Values the to check. Can give multipul vale separated 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 took 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.