none
Create Single Custom Disassembler Pipeline Compoenent for multiple schemas RRS feed

  • Question

  • I have two schema(Student,Employee) like below:

    

    The incoming message is flat file(.txt) like below :

    For Student Schema:

    Atul,Allahabd,102302,S1
    Arvind,Delhi,304305,S1
    Anand,Chennai,603203,S1

    For Employee Schema:

    A,10000,3,Biztalk,E1
    B,20000,5,C#,E1
    C,30000,7,Database,E1
    D,40000,9,Unix,E1

    Now I want to create a single custom disassembler component in which I can disassemble both schemas on the basis of Student_Transaction and Employee_Transaction element value.

    If, in flat file, Student_Transaction element value is S1 then disassemble Student schema and

    if,in flat file, Employee_Transaction element value is E1 then disassemble Employee schema.

    But both should be done with only one custom disassemble  component.

    Please tell me, how it is possible ?


    Prakash

    Friday, September 12, 2014 5:20 AM

Answers

  • Hi Prakash,

    I belive your issue has been going on for a while now (I can see another forum post which has been lots of replies but you're not able to get the solution from them, though some of the replies had the solution for you).

    Anyway, here is the code. As said in my replies in your other forum post, you could use Schema Resolver Component from SDK and update it for your requirement which is what I have done here.

    Do the following:

    • Define the flat-file schema for the above flat-file. Student and Employee
    • Deploy the schema.
    • Use the following code to custom flat-file disassembler component- which you have been try to develop.
    using System;
    using System.IO;
    using System.Collections;
    using System.Runtime.InteropServices;
    using System.Text;
    using Microsoft.BizTalk.Message.Interop;
    using Microsoft.BizTalk.Component.Interop;
    using Microsoft.BizTalk.Component;
    using Microsoft.Samples.BizTalk.Pipelines.CustomComponent;
    
    namespace Microsoft.Samples.BizTalk.Pipelines.SchemaResolver
    {
    	/// <summary>
    	/// Summary description for SchemaResolverFlatFileDasmComp.
    	/// </summary>
    	[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    	[ComponentCategory(CategoryTypes.CATID_DisassemblingParser)]
    	[Guid("E97DFAA6-EBD5-4999-A9C3-8C56DCAB898A")]
    	public class SchemaResolverFlatFileDasmComp : IBaseComponent, IDisassemblerComponent, IProbeMessage, IComponentUI
    	{
    		
    		public SchemaResolverFlatFileDasmComp()
    		{
    		}
    
    		#region IBaseComponent Members
    
    		public string Description
    		{
    			get
    			{
    				return "Flat file disassembler which resolves schemas using message contents";
    			}
    		}
    
    		public string Name
    		{
    			get
    			{
    				return "Schema resolving Flat File Disassembler";
    			}
    		}
    
    		public string Version
    		{
    			get
    			{
    				return "1.0";
    			}
    		}
    
    		#endregion
    
    		#region IDisassemblerComponent Members
    
    		public IBaseMessage GetNext(IPipelineContext pContext)
    		{
    			// Delegate call to Flat File disassembler
    			return disassembler.GetNext(pContext);
    		}
    
    		public void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
    		{
    			// Delegate call to Flat File disassembler
    			disassembler.Disassemble(pContext, pInMsg);
    		}
    
    		#endregion
    
    		#region IProbeMessage Members
    
    		public bool Probe(IPipelineContext pContext, IBaseMessage pInMsg)
    		{
                // Check arguments
    			if (null == pContext)
    				throw new ArgumentNullException("pContext");
    
    			if (null == pInMsg)
    				throw new ArgumentNullException("pInMsg");
    
    			// We need to determine a document schema to use based on message content. For the sake of simplicity of this
    			// sample, we will check the first two characters in input stream and map them to some schema message types we
    			// have predefined. The more sofisticated component could use UI configuration options to map identification 
    			// text located at specified offsets in message stream and having specified length, which could map to specified
    			// message type or document spec type name.
    
    			// Check whether input message doesn't have a body part or it is set to null, fail probe in those cases
    			if (null == pInMsg.BodyPart || null == pInMsg.BodyPart.GetOriginalDataStream())
    				return false;
    
    			SeekableReadOnlyStream stream = new SeekableReadOnlyStream(pInMsg.BodyPart.GetOriginalDataStream());
    			Stream sourceStream = pInMsg.BodyPart.GetOriginalDataStream();
    
    			// Check if source stream can seek
    			if (!sourceStream.CanSeek)
    			{
    				// Create a virtual (seekable) stream
    				SeekableReadOnlyStream seekableStream = new SeekableReadOnlyStream(sourceStream);
    
    				// Set new stream for the body part data of the input message. This new stream will then used for further processing.
    				// We need to do this because input stream may not support seeking, so we wrap it with a seekable stream.
    				pInMsg.BodyPart.Data = seekableStream;
    
    				// Replace sourceStream with a new seekable stream wrapper
    				sourceStream = pInMsg.BodyPart.Data;
    			}
    
    			// Preserve the stream position
    			long position = sourceStream.Position;
    
    			char [] signature = new char[2];
                string signaturValue = String.Empty;
    			try
    			{
    				// Read signature from a stream
    				StreamReader reader = new StreamReader(sourceStream);
                    if (reader.Read(signature, 0, signature.Length) < signature.Length)
                        return false;
    
                    string strOriginalData = reader.ReadToEnd();
                    //Get the last two character of the message, which will have identifier like S1 or E1
                    signaturValue = strOriginalData.Substring(strOriginalData.Length - 2, 2);
    
    
    
    				// Don't close stream reader to avoid closing of underlying stream
    			}
    			finally
    			{
    				// Restore the stream position
    				sourceStream.Position = position;
    			}
    
    			// Get message type from signature
    			//string messageType = GetMessageType(new string(signature));
                string messageType = GetMessageType(signaturValue);
    
    			// Fail if message type is unknown
    			if (null == messageType)
                    return false;
    
               
    
    			// Get document spec from the message type
    			IDocumentSpec documentSpec = pContext.GetDocumentSpecByType(messageType);
    
    			// Instead of loading schema to get a document spec type name we could change implementation to return defined 
    			// during a design time document spec type name and directly specify it in the call below:
    			
    			// Write document spec type name to the message context so Flat File disassembler could access this property and
    			// do message processing for a schema which has document spec type name we've discovered
    			pInMsg.Context.Write(DocumentSpecNamePropertyName, XmlNormNamespaceURI, documentSpec.DocSpecStrongName);
    
    			// Delegate call to Flat File disassembler
    			return disassembler.Probe(pContext, pInMsg);
    		}
    
    		#endregion
    
    		#region IComponentUI Members
    
    
    		public IntPtr Icon
    		{
    			get
    			{
    
    				return System.IntPtr.Zero;
    			}
    
    		}
    
    		/// <summary>
    		/// The Validate method is called by the BizTalk Editor during the build 
    		/// of a BizTalk project.
    		/// </summary>
    		/// <param name="obj">Project system.</param>
    		/// <returns>
    		/// A list of error and/or warning messages encounter during validation
    		/// of this component.
    		/// </returns>
    		public IEnumerator Validate(object obj)
    		{
    			return null;
    		}
    
    		#endregion
    
    		#region Private Members
    
    		/// <summary>
    		/// Gets message type for a signature
    		/// </summary>
    		/// <param name="signature">A signature</param>
    		/// <returns>Message type</returns>
    		private string GetMessageType(string signature)
    		{
    			InitializeMapping();
    			return (string) messageTypes[ signature ];
    		}
    
    		/// <summary>
    		/// Lazily initializes signature to message type mapping
    		/// </summary>
    		private static void InitializeMapping()
    		{
    			if (messageTypes != null)
    				return;
    
    			lock (typeof(SchemaResolverFlatFileDasmComp))
    			{
    				messageTypes = new Hashtable();
    
    				// Here document spec types names are hardcoded, in real implementation you need to specify them
    				// using design time properties.
                    //messageTypes[ "PO" ] = "http://schemas.biztalk.org/PO#PurchaseOrder";
                    //messageTypes[ "PR" ] = "http://schemas.biztalk.org/PR#PurchaseRequest";
                    //messageTypes[ "SO" ] = "http://schemas.biztalk.org/SO#SalesOrder";
                    //messageTypes[ "SR" ] = "http://schemas.biztalk.org/SR#SalesRequest";
    
                    //Replace the following 2 lines to the schema's message type in the format documentNameSpace#RootElement
                    messageTypes["S1"] = "http://Microsoft.Samples.BizTalk.Students#Students";
                    messageTypes["E1"] = "http://Microsoft.Samples.BizTalk.Employee#Employee";
    
    
    			}
    		}
    
    		private FFDasmComp disassembler = new FFDasmComp();
    		private static Hashtable messageTypes = null;
    		
    		private const string XmlNormNamespaceURI = "http://schemas.microsoft.com/BizTalk/2003/xmlnorm-properties";
    		private const string DocumentSpecNamePropertyName = "DocumentSpecName";
    
    		#endregion
    	}
    }
    

    • In the above you have to replace 2 lines to the message type of your schema which you have deployed for Student and Employee. I have commented the lines for you to replace. Look for comment is the code is"//Replace the following 2 lines to the schema's message type in the format documentNameSpace#RootElement". And update the message types to your deployed schema's message type.
    • Deploy this custom pipeline component.
    • Then in your BizTalk project, a custom Receive pipeline and in the Disassemble stage, add the above deployed custom pipeline component.

    This resolves the above two flat-files with just one Disassembler component as you're looking for. As said I have just updated the Schema Resolver Component from SDK to fit your requirement.


    If this answers your question please mark it accordingly. If this post is helpful, please vote as helpful by clicking the upward arrow mark next to my reply.

    • Marked as answer by Shivay_ Friday, September 12, 2014 8:32 AM
    Friday, September 12, 2014 8:22 AM
  • Create a custom validation pipeline component template using the pipeline component wizard and in the Execute method write your validation logic and for constructing a message with Error information. Your requirement is very much similar to

    Saravana's extended validation pipeline component.

    Where he validates the message and constructs a message with all the validation error in the message. You can use the later part of the code where message construction has been happening.


    If this answers your question please mark it accordingly. If this post is helpful, please vote as helpful by clicking the upward arrow mark next to my reply.


    • Edited by M.R.Ashwin Prabhu Thursday, September 18, 2014 1:48 PM
    • Marked as answer by Shivay_ Thursday, September 18, 2014 1:55 PM
    Thursday, September 18, 2014 1:47 PM
  • It's because static members are by default AppDomain static and can be accessed by any thread. To avoid concurrency issues (thread safety), access to an object should be blocked during change operations. Any blocked threads are released once the lock is released (in some other code bit I hope).

    GetNext - answered already.

    GetDocumentSpecByType retrieves the Schema, as an instance of IDocumentSpec type, for the given MessageType.

     
    • Marked as answer by Shivay_ Thursday, September 18, 2014 2:43 PM
    Thursday, September 18, 2014 2:40 PM
    Moderator

All replies

  • I suggest you take a look at  'Probing Pipeline Components'.
    http://msdn.microsoft.com/en-us/library/aa547871.aspx

    Here's some code example:
    http://blogs.msdn.com/b/brajens/archive/2007/01/28/how-to-develop-biztalk-custom-pipeline-components-part3.aspx



    Glenn Colpaert - MCTS BizTalk Server - Blog : http://blog.codit.eu

    Friday, September 12, 2014 6:31 AM
  • Hi Prakash,

    Create an Custom Disassembler Pipeline component and drop this pipeline component to the disassemble stage of an receive pipeline. Steps for your component can be :

    --> Use SelectSingleNode method to retreive value of the Student_Transaction or Employee_Transaction like below :

    string EmployeeORStudent = string.empty;

    EmployeeORStudent = xdoc.SelectSingleNode(

    @"/*[local-name()='Employee' and namespace-uri()='http://DisassemblerComponent_BT.Student']/*[local-name()='Student_Transaction' and namespace-uri()='']");

    EmployeeORStudent = xdoc.SelectSingleNode(

    @"/*[local-name()='Employee' and namespace-uri()='http://DisassemblerComponent_BT.Employee']/*[local-name()='Employee_Transaction' and namespace-uri()='']");

    Now in if() you can check the value of EmployeeORStudent and on the basis of this value you can loop around the records and do the debatching logic.

    ______________________________________________________________

    Please indicate "Mark as Answer" or "Mark as Helpful" if this post has answered the question

    Regards,

    Rahul Madaan

    biztalkvillage.blopspot.com

    Friday, September 12, 2014 7:08 AM
  • Hi Prakash,

    I belive your issue has been going on for a while now (I can see another forum post which has been lots of replies but you're not able to get the solution from them, though some of the replies had the solution for you).

    Anyway, here is the code. As said in my replies in your other forum post, you could use Schema Resolver Component from SDK and update it for your requirement which is what I have done here.

    Do the following:

    • Define the flat-file schema for the above flat-file. Student and Employee
    • Deploy the schema.
    • Use the following code to custom flat-file disassembler component- which you have been try to develop.
    using System;
    using System.IO;
    using System.Collections;
    using System.Runtime.InteropServices;
    using System.Text;
    using Microsoft.BizTalk.Message.Interop;
    using Microsoft.BizTalk.Component.Interop;
    using Microsoft.BizTalk.Component;
    using Microsoft.Samples.BizTalk.Pipelines.CustomComponent;
    
    namespace Microsoft.Samples.BizTalk.Pipelines.SchemaResolver
    {
    	/// <summary>
    	/// Summary description for SchemaResolverFlatFileDasmComp.
    	/// </summary>
    	[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    	[ComponentCategory(CategoryTypes.CATID_DisassemblingParser)]
    	[Guid("E97DFAA6-EBD5-4999-A9C3-8C56DCAB898A")]
    	public class SchemaResolverFlatFileDasmComp : IBaseComponent, IDisassemblerComponent, IProbeMessage, IComponentUI
    	{
    		
    		public SchemaResolverFlatFileDasmComp()
    		{
    		}
    
    		#region IBaseComponent Members
    
    		public string Description
    		{
    			get
    			{
    				return "Flat file disassembler which resolves schemas using message contents";
    			}
    		}
    
    		public string Name
    		{
    			get
    			{
    				return "Schema resolving Flat File Disassembler";
    			}
    		}
    
    		public string Version
    		{
    			get
    			{
    				return "1.0";
    			}
    		}
    
    		#endregion
    
    		#region IDisassemblerComponent Members
    
    		public IBaseMessage GetNext(IPipelineContext pContext)
    		{
    			// Delegate call to Flat File disassembler
    			return disassembler.GetNext(pContext);
    		}
    
    		public void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
    		{
    			// Delegate call to Flat File disassembler
    			disassembler.Disassemble(pContext, pInMsg);
    		}
    
    		#endregion
    
    		#region IProbeMessage Members
    
    		public bool Probe(IPipelineContext pContext, IBaseMessage pInMsg)
    		{
                // Check arguments
    			if (null == pContext)
    				throw new ArgumentNullException("pContext");
    
    			if (null == pInMsg)
    				throw new ArgumentNullException("pInMsg");
    
    			// We need to determine a document schema to use based on message content. For the sake of simplicity of this
    			// sample, we will check the first two characters in input stream and map them to some schema message types we
    			// have predefined. The more sofisticated component could use UI configuration options to map identification 
    			// text located at specified offsets in message stream and having specified length, which could map to specified
    			// message type or document spec type name.
    
    			// Check whether input message doesn't have a body part or it is set to null, fail probe in those cases
    			if (null == pInMsg.BodyPart || null == pInMsg.BodyPart.GetOriginalDataStream())
    				return false;
    
    			SeekableReadOnlyStream stream = new SeekableReadOnlyStream(pInMsg.BodyPart.GetOriginalDataStream());
    			Stream sourceStream = pInMsg.BodyPart.GetOriginalDataStream();
    
    			// Check if source stream can seek
    			if (!sourceStream.CanSeek)
    			{
    				// Create a virtual (seekable) stream
    				SeekableReadOnlyStream seekableStream = new SeekableReadOnlyStream(sourceStream);
    
    				// Set new stream for the body part data of the input message. This new stream will then used for further processing.
    				// We need to do this because input stream may not support seeking, so we wrap it with a seekable stream.
    				pInMsg.BodyPart.Data = seekableStream;
    
    				// Replace sourceStream with a new seekable stream wrapper
    				sourceStream = pInMsg.BodyPart.Data;
    			}
    
    			// Preserve the stream position
    			long position = sourceStream.Position;
    
    			char [] signature = new char[2];
                string signaturValue = String.Empty;
    			try
    			{
    				// Read signature from a stream
    				StreamReader reader = new StreamReader(sourceStream);
                    if (reader.Read(signature, 0, signature.Length) < signature.Length)
                        return false;
    
                    string strOriginalData = reader.ReadToEnd();
                    //Get the last two character of the message, which will have identifier like S1 or E1
                    signaturValue = strOriginalData.Substring(strOriginalData.Length - 2, 2);
    
    
    
    				// Don't close stream reader to avoid closing of underlying stream
    			}
    			finally
    			{
    				// Restore the stream position
    				sourceStream.Position = position;
    			}
    
    			// Get message type from signature
    			//string messageType = GetMessageType(new string(signature));
                string messageType = GetMessageType(signaturValue);
    
    			// Fail if message type is unknown
    			if (null == messageType)
                    return false;
    
               
    
    			// Get document spec from the message type
    			IDocumentSpec documentSpec = pContext.GetDocumentSpecByType(messageType);
    
    			// Instead of loading schema to get a document spec type name we could change implementation to return defined 
    			// during a design time document spec type name and directly specify it in the call below:
    			
    			// Write document spec type name to the message context so Flat File disassembler could access this property and
    			// do message processing for a schema which has document spec type name we've discovered
    			pInMsg.Context.Write(DocumentSpecNamePropertyName, XmlNormNamespaceURI, documentSpec.DocSpecStrongName);
    
    			// Delegate call to Flat File disassembler
    			return disassembler.Probe(pContext, pInMsg);
    		}
    
    		#endregion
    
    		#region IComponentUI Members
    
    
    		public IntPtr Icon
    		{
    			get
    			{
    
    				return System.IntPtr.Zero;
    			}
    
    		}
    
    		/// <summary>
    		/// The Validate method is called by the BizTalk Editor during the build 
    		/// of a BizTalk project.
    		/// </summary>
    		/// <param name="obj">Project system.</param>
    		/// <returns>
    		/// A list of error and/or warning messages encounter during validation
    		/// of this component.
    		/// </returns>
    		public IEnumerator Validate(object obj)
    		{
    			return null;
    		}
    
    		#endregion
    
    		#region Private Members
    
    		/// <summary>
    		/// Gets message type for a signature
    		/// </summary>
    		/// <param name="signature">A signature</param>
    		/// <returns>Message type</returns>
    		private string GetMessageType(string signature)
    		{
    			InitializeMapping();
    			return (string) messageTypes[ signature ];
    		}
    
    		/// <summary>
    		/// Lazily initializes signature to message type mapping
    		/// </summary>
    		private static void InitializeMapping()
    		{
    			if (messageTypes != null)
    				return;
    
    			lock (typeof(SchemaResolverFlatFileDasmComp))
    			{
    				messageTypes = new Hashtable();
    
    				// Here document spec types names are hardcoded, in real implementation you need to specify them
    				// using design time properties.
                    //messageTypes[ "PO" ] = "http://schemas.biztalk.org/PO#PurchaseOrder";
                    //messageTypes[ "PR" ] = "http://schemas.biztalk.org/PR#PurchaseRequest";
                    //messageTypes[ "SO" ] = "http://schemas.biztalk.org/SO#SalesOrder";
                    //messageTypes[ "SR" ] = "http://schemas.biztalk.org/SR#SalesRequest";
    
                    //Replace the following 2 lines to the schema's message type in the format documentNameSpace#RootElement
                    messageTypes["S1"] = "http://Microsoft.Samples.BizTalk.Students#Students";
                    messageTypes["E1"] = "http://Microsoft.Samples.BizTalk.Employee#Employee";
    
    
    			}
    		}
    
    		private FFDasmComp disassembler = new FFDasmComp();
    		private static Hashtable messageTypes = null;
    		
    		private const string XmlNormNamespaceURI = "http://schemas.microsoft.com/BizTalk/2003/xmlnorm-properties";
    		private const string DocumentSpecNamePropertyName = "DocumentSpecName";
    
    		#endregion
    	}
    }
    

    • In the above you have to replace 2 lines to the message type of your schema which you have deployed for Student and Employee. I have commented the lines for you to replace. Look for comment is the code is"//Replace the following 2 lines to the schema's message type in the format documentNameSpace#RootElement". And update the message types to your deployed schema's message type.
    • Deploy this custom pipeline component.
    • Then in your BizTalk project, a custom Receive pipeline and in the Disassemble stage, add the above deployed custom pipeline component.

    This resolves the above two flat-files with just one Disassembler component as you're looking for. As said I have just updated the Schema Resolver Component from SDK to fit your requirement.


    If this answers your question please mark it accordingly. If this post is helpful, please vote as helpful by clicking the upward arrow mark next to my reply.

    • Marked as answer by Shivay_ Friday, September 12, 2014 8:32 AM
    Friday, September 12, 2014 8:22 AM
  • It's probably not a good idea to read the entire message content into a string:

    string strOriginalData = reader.ReadToEnd();

    Given the above examples, the message type can determined by reading just the first line:

    string strOriginalData = reader.ReadLine();

    Friday, September 12, 2014 4:02 PM
    Moderator
  • Hi Ashwin,

    Can you explain the following line of code in the above code given by you:

     private static void InitializeMapping()
            {
                EventLog.WriteEntry("Enter into Resolver Component:InitializeMapping", "");
                if (messageTypes != null)
                {
                    EventLog.WriteEntry("Enter into Resolver Component:InitializeMapping:if (messageTypes != null)", "");
                    return;
                }
                    lock(typeof(ResolverComponent))
                {
                    EventLog.WriteEntry("Enter into Resolver Component:InitializeMapping:lock(typeof(ResolverComponent))", "");
                    messageTypes = new Hashtable();
                    messageTypes["S1"] = "http://Disassembler_SingleComponent.StudentSchema#StudentDetails";
                    messageTypes["E1"] = "http://Disassembler_SingleComponent.EmployeeSchema#EmployeeDetails";
                    EventLog.WriteEntry("Enter into Resolver Component:InitializeMapping:messageTypes[S1]", messageTypes["S1"].ToString());
                    EventLog.WriteEntry("Enter into Resolver Component:InitializeMapping:messageTypes[E1])", messageTypes["E1"].ToString());
                
                }
            }


    what is the use of lock here ?I run my code without using lock and it is working fine.

    Please explain.

    Also explain that why GetNext() execute two times ?I checked it on EventLogs.

    Also explain the following line of code in the above 

    IDocumentSpec documentSpec = pContext.GetDocumentSpecByType(messageType);
      pInMsg.Context.Write(DocumentSpecNamePropertyName, XmlNormNamespaceURI, documentSpec.DocSpecStrongName);



    Prakash





    • Edited by Shivay_ Thursday, September 18, 2014 10:23 AM
    Thursday, September 18, 2014 7:07 AM
  • Now My input schema is as follows:

    if Input message is as follows:

    Prakash,Sajwan,S1
    vIKASH,Dhangwal,S1

    the output should be as follows:

    I am getting it by your given code in custom disassembler by implementing IProbe method.

    But if Input message is as follows:

    Prakash,Sajwan,S2

    Then I want the following output:

    <ns0:StudentDetails xmlns:ns0="http://Disassembler_SingleComponent.StudentSchema">
      <Student FName="Prakash" LName="Sajwan" TransactionType="S2" /> 

     <Errors>
      <Error NodeName="TransactionType" Description="TransactionType has invalid values" /> 
      </Errors>
      </ns0:StudentDetails>

    I want to done it in disassembling stage not in orchestration.

    Please help.


    Prakash

    Thursday, September 18, 2014 10:48 AM
  • This is not the functionality of a dissemble component, if you want to do it correct way. This has to be in validate component. And in the validate component you have to construct the Error section while emitting the message.


    If this answers your question please mark it accordingly. If this post is helpful, please vote as helpful by clicking the upward arrow mark next to my reply.

    Thursday, September 18, 2014 1:25 PM
  • Can you provide some link by which I can get help for creating custom validator component ?

    For using custom validator which Interface should I implement ?


    Prakash

    Thursday, September 18, 2014 1:29 PM
  • Hi Prakash,

    Try this http://blogs.msdn.com/brajens/archive/2006/11/25/how-to-develop-biztalk-custom-pipeline-components-part1.aspx

    Another 1- http://www.bizbert.com/bizbert/CommentView,guid,c04612b1-f77d-4cb8-bdb5-ff6acf5b1790.aspx

    Rachit


    Thursday, September 18, 2014 1:37 PM
    Moderator
  • Hi Rachit,

    The link given by you is for custom decoder not for custom validator.


    Prakash

    Thursday, September 18, 2014 1:41 PM
  • Create a custom validation pipeline component template using the pipeline component wizard and in the Execute method write your validation logic and for constructing a message with Error information. Your requirement is very much similar to

    Saravana's extended validation pipeline component.

    Where he validates the message and constructs a message with all the validation error in the message. You can use the later part of the code where message construction has been happening.


    If this answers your question please mark it accordingly. If this post is helpful, please vote as helpful by clicking the upward arrow mark next to my reply.


    • Edited by M.R.Ashwin Prabhu Thursday, September 18, 2014 1:48 PM
    • Marked as answer by Shivay_ Thursday, September 18, 2014 1:55 PM
    Thursday, September 18, 2014 1:47 PM
  • From the other thread:

    Also, what you are asking for specifically there, errors to be appended to the document, is not possible with any built-in component.  That would have to be an entirely custom implementation.

    Detecting such 'error' conditions is best done in a Map where you can either A) correct them (reformate to Vikash) or B) flag the record as invalid where it will be handled by a downstream process.

    Thursday, September 18, 2014 1:55 PM
    Moderator
  • Thanks Ashwin for the reply,

    I will look into that code, if want any help then ask you again but I don't want to construct message with the help of mapping.

     I want the following output:

    <ns0:StudentDetails xmlns:ns0="http://Disassembler_SingleComponent.StudentSchema">
      <Student FName="Prakash" LName="Sajwan" TransactionType="S2" /> 

     <Errors>
      <Error NodeName="TransactionType" Description="TransactionType has invalid values" /> 
      </Errors>
      </ns0:StudentDetails>

    in validator component.


    Prakash

    Thursday, September 18, 2014 2:00 PM
  • Can anyone explain the following line of code in the above code :

     private static void InitializeMapping()
            {
                EventLog.WriteEntry("Enter into Resolver Component:InitializeMapping", "");
                if (messageTypes != null)
                {
                    EventLog.WriteEntry("Enter into Resolver Component:InitializeMapping:if (messageTypes != null)", "");
                    return;
                }
                    lock(typeof(ResolverComponent))
                {
                    EventLog.WriteEntry("Enter into Resolver Component:InitializeMapping:lock(typeof(ResolverComponent))", "");
                    messageTypes = new Hashtable();
                    messageTypes["S1"] = "http://Disassembler_SingleComponent.StudentSchema#StudentDetails";
                    messageTypes["E1"] = "http://Disassembler_SingleComponent.EmployeeSchema#EmployeeDetails";
                    EventLog.WriteEntry("Enter into Resolver Component:InitializeMapping:messageTypes[S1]", messageTypes["S1"].ToString());
                    EventLog.WriteEntry("Enter into Resolver Component:InitializeMapping:messageTypes[E1])", messageTypes["E1"].ToString());
                
                }
            }

    what is the use of lock here ?I run my code without using lock and it is working fine.

    Please explain.

    Also explain that why GetNext() execute two times ?I checked it on EventLogs.

    Also explain the following line of code in the above code:

    IDocumentSpec documentSpec = pContext.GetDocumentSpecByType(messageType);
      pInMsg.Context.Write(DocumentSpecNamePropertyName, XmlNormNamespaceURI, documentSpec.DocSpecStrongName);

    Prakash

    Thursday, September 18, 2014 2:02 PM
  •  I want the following output:

    <...>

    in validator component.

    That is not possible unless you write your own custom Pipeline Component.

    Thursday, September 18, 2014 2:29 PM
    Moderator
  • It's because static members are by default AppDomain static and can be accessed by any thread. To avoid concurrency issues (thread safety), access to an object should be blocked during change operations. Any blocked threads are released once the lock is released (in some other code bit I hope).

    GetNext - answered already.

    GetDocumentSpecByType retrieves the Schema, as an instance of IDocumentSpec type, for the given MessageType.

     
    • Marked as answer by Shivay_ Thursday, September 18, 2014 2:43 PM
    Thursday, September 18, 2014 2:40 PM
    Moderator
  • Obviously John,It will be possible through custom pipeline component.


    Prakash

    Thursday, September 18, 2014 2:46 PM
  • Hi Ashwin,
    I looked into that code of Saravana's extended validation pipeline component. but in that code he used mapping and call that
    custom validation pipeline component in orchestration.
    But my requirement is that I have to create error message in custom pipeline and then send this error message to send port through filter conditions.

    I tried my best but not got the right solution.Actually in that code,the validation errors goes into catch section of Execute():
               
           catch (Exception exception2)
                {
                  //  EventLog.WriteEntry("Enter into Catch Block Execute() Exception", exception2.ToString());

                    ComponentException.StoreException(pc, exception2, this.Name);
                    throw exception2;
                }

    and after that it is difficult to track that exception error.


    Prakash

    Monday, September 22, 2014 12:08 PM
  • I'll be totally honest here.  If you are doing everything you've been asking about, it's difficult to track the exception because you're making it harder than it needs to be.

    Debatching in a Receive Pipeline, even with multiple Receive Locations and applying these types of rules in an Orchestration with a Map or BRE Policy is almost trivial.

    I've asked several times what exact considerations sent you down this path.  I'd rather address those instead of piling on to a difficult situation.

    Monday, September 22, 2014 12:59 PM
    Moderator