locked
BizTalk C# custom Pipeline component - Issue RRS feed

  • Question

  • Iam using below code to archieve any message coming in.... Using this in Disassemble stage.

    Receiving following error on dropping a file : what am I doing wrong ?

    There was a failure executing the receive pipeline: "BizTalk.Archiving.Solution.Pipelines.ReceivePipelineArchive, BizTalk.Archiving.Solution.Pipelines, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5aa8b1d838f63155" Source: "Unknown " Receive Port: "TestArchieveIn" URI: "C:\Users\Test\Desktop\PipelineArchieve\In\*.*" Reason: Could not load file or assembly 'file:///C:\Program Files (x86)\Microsoft BizTalk Server 2013 R2\Pipeline Components\BizTalk.Archiving.Solution.Pipeline.Components.dll' or one of its dependencies. The system cannot find the file specified.

       public void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
            {
                //Trace 
                System.Diagnostics.Debug.WriteLine("1.  Pipeline Disassemble Stage");
    
                //Create XmlDocument object
                XmlDocument xmlDoc = new XmlDocument();
    
                //Create a copy of the message
                IBaseMessage archiveMessage = pInMsg;
    
                //Trace
                System.Diagnostics.Debug.WriteLine("2.  Call GetMessagePayLoad()");
    
                //Get Message PayLoad
                xmlDoc = GetMessagePayLoad(archiveMessage);
    
                //Trace
                System.Diagnostics.Debug.WriteLine("3.  Message PayLoad :" + xmlDoc.OuterXml);
    
                // Promote MessageType in order to the Biztalk to have a unique key for evaluating the subscription
                archiveMessage.Context.Promote("MessageType", "http://schemas.microsoft.com/BizTalk/2003/system-properties", xmlDoc.DocumentElement.NamespaceURI + "#" + xmlDoc.DocumentElement.LocalName.ToString());
    
                //Debug 
                System.Diagnostics.Trace.WriteLine("4. Call ReadContextProperties");
    
                //Get the context properties and assign them to contextProperties  archiveMessage
                string contextProperties = ReadContextProperties(archiveMessage);
    
                //Debug 
                System.Diagnostics.Trace.WriteLine("5. Context Properties: " + contextProperties);
    
                //Get the message content (BodyPart)
                string messageBody = xmlDoc.OuterXml;
    
                //Debug 
                System.Diagnostics.Trace.WriteLine("6. Message Body: " + messageBody);
    
                //Debug 
                System.Diagnostics.Trace.WriteLine("7. Write to output file");
    
                //Write output
                using (StreamWriter outfile = new StreamWriter(_ArchiveLocation + System.Guid.NewGuid().ToString() + "_Message" + ".txt"))
                {
    
                    //Debug 
                    System.Diagnostics.Trace.WriteLine("8. File Location :" + _ArchiveLocation);
    
                    outfile.Write(contextProperties + " " + Environment.NewLine + messageBody);
    
                    //Debug 
                    System.Diagnostics.Trace.WriteLine("9. Write to output file");
                }
    
                //Debug 
                System.Diagnostics.Trace.WriteLine("10. Pipeline Disassemble Stage Exit");
    
    
                //Return orginal message
                IBaseMessage outMessage;
                outMessage = pContext.GetMessageFactory().CreateMessage();
                outMessage.AddPart("Body", pContext.GetMessageFactory().CreateMessagePart(), true);
                IBaseMessagePart bodyPart = pInMsg.BodyPart;
                Stream originalStream = bodyPart.GetOriginalDataStream();
                originalStream.Position = 0;
                outMessage.BodyPart.Data = originalStream;
    
                outMessage.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);
    
                _qOutMessages.Enqueue(outMessage);
                
                //Return orginal message to queue
                _qOutMessages.Enqueue(outMessage);
            }
    
            /// <summary>
            /// Default method
            /// </summary>
            /// <param name="pContext">Context</param>
            /// <returns>null</returns>
            public IBaseMessage GetNext(IPipelineContext pContext)
            {
                if (_qOutMessages.Count > 0)
                {
                    IBaseMessage msg = (IBaseMessage)_qOutMessages.Dequeue();
                    return msg;
                }
                else
                    return null;
    
            }
    
            /// <summary>
            /// Read the context properties of the message
            /// </summary>
            /// <param name="archiveMessage">IBaseMessage archiveMessage</param>
            /// <returns>string containing all context properties</returns>
            private string ReadContextProperties(IBaseMessage archiveMessage)
            {
                string name;
                string nmspace;
                string contextItems = "";
    
                for (int x = 0; x < archiveMessage.Context.CountProperties; x++)
                {
                    archiveMessage.Context.ReadAt(x, out name, out nmspace);
                    string value = archiveMessage.Context.Read(name, nmspace).ToString();
                    contextItems += "Name: " + name + " - " + "Namespace: " + nmspace + " - " + value + "\r\n";
                }
    
                return contextItems;
            }
    
            /// <summary>
            /// Method extract message into XMLDocument
            /// </summary>
            /// <param name="archiveMessage">IBaseMessage</param>
            /// <returns>XML Document</returns>
            private XmlDocument GetMessagePayLoad(IBaseMessage archiveMessage)
            {
                IBaseMessagePart bodyPart = archiveMessage.BodyPart;
                Stream originalStream = bodyPart.GetOriginalDataStream();
    
                XmlDocument XMlDoc = new XmlDocument();
                XMlDoc.Load(originalStream);
    
                return XMlDoc; 
            }


    MBH

    Wednesday, August 26, 2015 6:11 PM

Answers

  • Hi,

    You error is situated around 'Could not load file or assembly 'file:///C:\Program Files (x86)\Microsoft BizTalk Server 2013 R2\Pipeline Components\BizTalk.Archiving.Solution.Pipeline.Components.dll' or one of its dependencies.' and that is were problem lies.

    Pipeline needs to be properly signed, build and deployed (latter two dependencies play a role). If that is not the case that the error will keep popping up.

    check this thread. This might help you

    http://social.msdn.microsoft.com/Forums/en/biztalkgeneral/thread/2f1d1a88-dca6-4498-ab23-033326613c09


    Thanks, If my reply is helpful please mark as answer or vote as helpful.

    • Marked as answer by Angie Xu Monday, September 14, 2015 12:13 AM
    Wednesday, August 26, 2015 6:22 PM
    Moderator
  • Do not put any Pipeline Component Assemblies in the %Pipelines Components% folder.

    This article describes the correct process for developing and deploying custom Pipeline Components:

    BizTalk: Deploying Custom Pipeline Components in BizTalk Server 2006 and Higher

    This looks like some sample code.  It's not a very good implementation as there are two significant issues I would not allow:

    1. Using XmlDocument - this is a performance issue as there are much less expensive ways to handle this.
    2. The technique to Promote BTS.MessageType is technically not complete and will not work in all scenarios.

    • Marked as answer by Angie Xu Monday, September 14, 2015 12:13 AM
    Wednesday, August 26, 2015 6:23 PM
    Moderator

All replies

  • Hi,

    You error is situated around 'Could not load file or assembly 'file:///C:\Program Files (x86)\Microsoft BizTalk Server 2013 R2\Pipeline Components\BizTalk.Archiving.Solution.Pipeline.Components.dll' or one of its dependencies.' and that is were problem lies.

    Pipeline needs to be properly signed, build and deployed (latter two dependencies play a role). If that is not the case that the error will keep popping up.

    check this thread. This might help you

    http://social.msdn.microsoft.com/Forums/en/biztalkgeneral/thread/2f1d1a88-dca6-4498-ab23-033326613c09


    Thanks, If my reply is helpful please mark as answer or vote as helpful.

    • Marked as answer by Angie Xu Monday, September 14, 2015 12:13 AM
    Wednesday, August 26, 2015 6:22 PM
    Moderator
  • Do not put any Pipeline Component Assemblies in the %Pipelines Components% folder.

    This article describes the correct process for developing and deploying custom Pipeline Components:

    BizTalk: Deploying Custom Pipeline Components in BizTalk Server 2006 and Higher

    This looks like some sample code.  It's not a very good implementation as there are two significant issues I would not allow:

    1. Using XmlDocument - this is a performance issue as there are much less expensive ways to handle this.
    2. The technique to Promote BTS.MessageType is technically not complete and will not work in all scenarios.

    • Marked as answer by Angie Xu Monday, September 14, 2015 12:13 AM
    Wednesday, August 26, 2015 6:23 PM
    Moderator
  • so is there anyway I can update my code ? The purpose of the code is to the Archieve the file into a folder and parallely process it.

    MBH

    Wednesday, August 26, 2015 6:33 PM
  • Hi,

    You can use BizTalk stream based archiving pipeline component. Below is the sample code for Archiving Pipeline component using stream. It will take you less memory while execution .

            public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
            {
                if (_ArchiveFiles)
                {
                    string archiveFileName = inmsg.Context.Read(_FileNameProperty, _FileNamePropertyNamespace) as string;
                    if (archiveFileName != null && !string.IsNullOrEmpty(archiveFileName))
                    {
                        if (archiveFileName.Contains("\\"))
                            archiveFileName = archiveFileName.Substring(archiveFileName.LastIndexOf("\\") + 1);
    
                        ArchivingStream archivingStream = new ArchivingStream(inmsg.BodyPart.Data, _ArchivePath + "\\" + archiveFileName);
                        pc.ResourceTracker.AddResource(archivingStream);
                        inmsg.BodyPart.Data = archivingStream;
                    }
                }

    You can download complete code at https://code.msdn.microsoft.com/BizTalk-stream-based-d6ef0f1f

    Thanks

    Abhishek

    Wednesday, August 26, 2015 7:00 PM
  • Hi Jaguarajags,

    - Ensure all the dependent dll's are there in assembly before testing, you can debug and see at which state / line its throwing exception if you are not sure about the dependent dll reference.

    - You can keep two different components in receive pipeline (for decoupling, not mandatory).

        - Archive component - i see you are saving context properties also.

        - Your custom component for message processing which you are written.

    Added for your reference:

    -  There is a general sample pipeline components for archiving the files.

         You can have a look with the below sample component and then you can create for your scenario.

    https://biztalkarchiving.codeplex.com/

    https://code.msdn.microsoft.com/BizTalk-stream-based-d6ef0f1f/sourcecode?fileId=54300&pathId=399221656

    Thanks, SMSVikasK


    Wednesday, August 26, 2015 7:06 PM
    Answerer
  • Hi Abhishek, in what stage do I need to put this method ? Execute in c# Custom pipeline ?

    MBH

    Wednesday, August 26, 2015 7:49 PM
  • Have you fully evaluated BizTalk Tracking?  It essentially 'archives' the incoming message out of the box.

    This is also assuming you have a triple confirmed business requirement to archive the messages.

    Do not try to modify that code, it will take an unreasonable amount of time to 'correct' it.

    There are a number of better components out there, for example: http://biztalkarchiving.codeplex.com/SourceControl/latest#Source/Common/MessageArchiver.cs

    Also, the link to the complete code for that example is provided right in Abhishek0127's post.

    Wednesday, August 26, 2015 7:50 PM
    Moderator
  • Hi Jaguarjags,

    Decode Stage would be better.

    Thanks, SMSVikasK

    Wednesday, August 26, 2015 8:08 PM
    Answerer
  • Hi SMSVikasK,

    If you want to archive a copy of the inbound file for some other process to deal with it, you could just set up a subscription to either the Receive Port (not good practice as it is tightly coupled), or to the inbound message type and a promoted property, such as Status.

    This property could be promoted in a pipeline component and then it's just simple content based routing to archive the file.

    Cheers,

    Martin

    Thursday, August 27, 2015 3:56 AM
  • Hi CompetitiveDad,

    I agree with you, for your approach.

    jaguarjags want to save the context property also with the message content.

    Normally many people prefer in component level so that they can reuse that component in multiple pipelines, applications to avoid creating send ports (i used to follow this pattern, sharing my thoughts).

    Thanks, SMSVikasK




    Thursday, August 27, 2015 4:57 AM
    Answerer
  • Hi Abhishek, in what stage do I need to put this method ? Execute in c# Custom pipeline ?

    MBH

    You can just put the code in the decode stage .  The code mentioned in   https://code.msdn.microsoft.com/BizTalk-stream-based-d6ef0f1f will work only you need to Migrate the code to the version of BizTalk you are using .

    Thanks

    Abhishek

    Thursday, August 27, 2015 5:45 AM
  • Why are you using a custom built compoennt if ur requirement is just to archive the incoming file as well as process it.

    You can very well create subscription on ur receiveport on a sendport and send the original message out. Ur processing orch will anyway process the incoming message.

    Multiple subscription can easily be done in this case.


    Regards &lt;br/&gt; When you see answers and helpful posts,&lt;br/&gt; please click Vote As Helpful, Propose As Answer, and/or Mark As Answer

    Thursday, August 27, 2015 6:00 AM
    Answerer
  • Hey SMSVikasK,

    We just created a simple pipeline component that takes a list of objects that contain a namespace, property and value and promotes them.

    We have a set of common properties across our messages and use them for routing decisions, and because the properties and the property promotion pipeline component are common they get extensive reuse.

    Of course you can use BTS.ReceivePortName as mentioned, but all the messages in our solutions need additional property enrichment for other routing decisions so using a pipeline component gives us a bit more flexibility.

    Cheers,

    Martin

    Thursday, August 27, 2015 7:17 AM
  • Hi jaguarjags,

    Hope you have fixed dependencies error ?

    if not let us know, will try to help you.

    Thanks,SMSVikasK

    Friday, August 28, 2015 10:16 AM
    Answerer
  • Receiving following error : the Type or namespace Bitmap does not exist in the namepace 'System.Drawing'.

     public IntPtr Icon
            {
                get
                {
                    return ((System.Drawing.Bitmap)(this.resourceManager.GetObject("COMPONENTICON", System.Globalization.CultureInfo.InvariantCulture))).GetHicon();
                }
            }


    MBH

    Friday, August 28, 2015 5:41 PM
  • Receiving following error : the Type or namespace Bitmap does not exist in the namepace 'System.Drawing'.

     public IntPtr Icon
            {
                get
                {
                    return ((System.Drawing.Bitmap)(this.resourceManager.GetObject("COMPONENTICON", System.Globalization.CultureInfo.InvariantCulture))).GetHicon();
                }
            }


    MBH

    Please verify below steps,

    1. Verify reference added
    2. Verify Namespace added using System.Drawing;
    3. Verify you have changed .NET Framework version to .NET 4.0

    For adding reference,

    * Right click to references, which is under solution,
    * add reference
    * add system.drawing

    Check Target framework

    * Right click on properties of Console Application.
    * Check Target framework
    * If it is .net framework 4.0 Client Profile than change it to .NET Framework 4.0


    Thanks, If my reply is helpful please mark as answer or vote as helpful.

    Friday, August 28, 2015 5:50 PM
    Moderator
  • Is this related to same error thread, If not then please open new thread.

    Thanks, If my reply is helpful please mark as answer or vote as helpful.

    Friday, August 28, 2015 5:52 PM
    Moderator
  • Please, can you let us know if you have chose a different archive component?

    The one referenced in the original post is not a production ready implementation and can cause more problems that it 'solves'.

    Friday, August 28, 2015 6:04 PM
    Moderator
  • I followed below link :

    https://code.msdn.microsoft.com/BizTalk-stream-based-d6ef0f1f

    when I built and deployed the project, placed the Pipeline in Decode stage. When selecting in ReceivePipeline and dropping the message, receiving below error :

    There was a failure executing the receive pipeline: "company.Integration.ArchieveFiles.ArchievePP, company.Integration.ArchieveFiles, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5aa8b1d838f63155" Source: "StreamingArchiveComponent" Receive Port: "TestInpp" URI: "C:\Users\Desktop\TodayTest\In\*.*" Reason: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.


    MBH

    Friday, August 28, 2015 7:09 PM
  • I followed below link :

    https://code.msdn.microsoft.com/BizTalk-stream-based-d6ef0f1f

    when I built and deployed the project, placed the Pipeline in Decode stage. When selecting in ReceivePipeline and dropping the message, receiving below error :

    There was a failure executing the receive pipeline: "company.Integration.ArchieveFiles.ArchievePP, company.Integration.ArchieveFiles, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5aa8b1d838f63155" Source: "StreamingArchiveComponent" Receive Port: "TestInpp" URI: "C:\Users\Desktop\TodayTest\In\*.*" Reason: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.


    MBH

    Have you try to receive the message using the pass through pipeline?

    Do you have access the file on receive location?


    Thanks, If my reply is helpful please mark as answer or vote as helpful.

    Friday, August 28, 2015 7:23 PM
    Moderator
  • Yes, when using Pass through pipeline message is getting picked. But when I change to this custom component by selecting this pipeline receiving below error :

    There was a failure executing the receive pipeline: "Company.Integration.ArchieveFiles.ArchievePP, Company.Integration.ArchieveFiles, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5aa8b1d838f63155" Source: "StreamingArchiveComponent" Receive Port: "TestInpp" URI: "C:\Users\Desktop\TodayTest\In\*.*" Reason: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.


    MBH

    Friday, August 28, 2015 8:22 PM
  • I concur on closing this thread and opening a new one as this is a different issue.

    This should be pretty easy to debug.  Attach Visual Studio and it should break on the statement causing the error.

    Friday, August 28, 2015 8:26 PM
    Moderator
  • Please open a new thread with your question.

    Close this thread and mark your answer.


    Thanks, If my reply is helpful please mark as answer or vote as helpful.

    Friday, August 28, 2015 8:29 PM
    Moderator