Tallan's Technology Blog

Tallan's Top Technologists Share Their Thoughts on Today's Technology Challenges

Custom Pipeline Components – part 3: Completing the Archive Component

This post continues the series on creating custom pipeline components. The previous posts in the series can be found here:  post 1,  post 2.

In order to complete the exercise of creating the archive component, we need to add the code to actually perform the archival of the message. For this example, the requirements of the archive component is to persist an exact copy of the message coming into BizTalk (whether flat file, xml, binary or even an encrypted) in it’s original form to the local filesystem.

To start off, we need to create a method to write an inputstream to the filesystem outputstream. The following CopyStream method does this…

        protected void CopyStream(Stream input, Stream output)

        {

            int BUFFER_SIZE = 4096;

            byte[] buffer = new byte[BUFFER_SIZE];

            int bytesRead;

            try

            {

                bytesRead = input.Read(buffer, 0, BUFFER_SIZE);

                while (bytesRead > 0)

                {

                    output.Write(buffer, 0, bytesRead);

                    bytesRead = input.Read(buffer, 0, BUFFER_SIZE);

                }

            }

            catch (Exception ex)

            {

                throw ex;

            }

            finally

            {

                // rewind input stream

                if (input.CanSeek)

                    input.Position = 0;

            }

        }

The next method needed is one that takes a BizTalk IBaseMessage and uses the CopyStream method from above to write the message to the filesystem.

        protected void WriteToFile(IBaseMessage message, string fileName)

        {

            Stream msgStream = message.BodyPart.GetOriginalDataStream();

            FileStream fileStream = null;

            try

            {

                fileStream = new FileStream(fileName, FileMode.OpenOrCreate);

                this.CopyStream(msgStream, fileStream);

            }

            catch (Exception ex)

            {

                throw ex;

            }

            finally

            {

                if (fileStream != null)

                    fileStream.Close();

                if (msgStream.CanSeek)

                    msgStream.Position = 0;

            }

        }

The final step is to  implement the Execute method that utilizes the WriteToFile method we just created. We will use the InterchangeID as the filename, and since it is basically a GUID it guarantees the filename will be unique. This is a string automatically set by the Messaging Engine for each message that arrives on the server and it defines the unique ID that is used to group the documents that resulted from the same interchange message.

We also want to the archive file to include the original filename, otherwise it might be difficult for a user to determine which message came from which file when a directory is filled with just GUIDs. So what we will do is look at the original filename property and prepend it to the InterchangeID with a underscore between them. You will notice that depending on the adapter (FILE, FTP) the file comes in on, we use a different schema. In addition, if the file comes in from any other adapter, the filename property won’t be available, so we skip the prepend step.

        /// <summary>

        /// Implements IComponent.Execute method.

        /// </summary>

        /// <param name=”pc”>Pipeline context</param>

        /// <param name=”inmsg”>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>

        public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute

                     (Microsoft.BizTalk.Component.Interop.IPipelineContext pContext,

                      Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)

        {

            IBaseMessage passedMessage = pInMsg;

            string archiveFileName = null;

            // get the interchange id from the message

            string interchangeID = (string)pInMsg.Context.Read(“InterchangeID”,

                “http://schemas.microsoft.com/BizTalk/2003/system-properties”);

            // if the transport type if file or ftp, get the incoming filename to use

            // as part of the archive filename (for easier identification)

            string filePath = null;

            string adapterType = (string)pInMsg.Context.Read(“InboundTransportType”,

                “http://schemas.microsoft.com/BizTalk/2003/system-properties”);

            if (adapterType == “FILE”)

            {

                filePath = (string)pInMsg.Context.Read(“ReceivedFileName”,

                    “http://schemas.microsoft.com/BizTalk/2003/file-properties”);

            }

            else if (adapterType == “FTP”)

            {

                filePath = (string)pInMsg.Context.Read(“ReceivedFileName”,

                    “http://schemas.microsoft.com/BizTalk/2003/ftp-properties”);

            }

            archiveFileName = interchangeID + “.out”;

            if (filePath != null)

            {

                archiveFileName = Path.GetFileName(filePath) + “_” + archiveFileName;

            }

            // write the archive file

            WriteToFile(pInMsg, Path.Combine(this._ArchivePath, archiveFileName));

            // this way, it’s a passthrough pipeline component

            return
pInMsg;

        }

        #endregion

When used, the archive component will create files with filenames similar to the following examples:

If Transport Type = FTP  or FILE:

MyTestFile.txt.pgp_{2E50A0DD-395B-4629-A345-7CB0FDDE4727}.out

Any other Transport Type:

{B9D33010-BE49-490B-ABFA-E3B63CAFCDAE}.out

The next article in this series goes over the steps to using the custom Archive pipeline component in your BizTalk application.

Tags: BizTalk,

5 Comments. Leave new

Daniel Hester
March 15, 2007 1:30 pm

Great article! One quibble. In the Public Execute method you declare IBaseMessage passedMessage = pInMsg but you don’t actually do anything with it?

I would recommend:
IBaseMessagePart bodyPart = pInMsg.BodyPart;
if (bodyPart != null) {
//Insert your code here
}

Good job!

Hi! I was surfing and found your blog post… nice! I love your blog. :) Cheers! Sandra. R.

Hi, where we are capture the xml document finally, earlier you have used path some thing like , but you never usee that path while send file to that path can you please send that code which is working
early reposnse appreciate

Hi can you give me the continuation of this part of about how to use this pipeline in the receive port.
Thank you so much for the help your blog was so much helpfull.

Hi can you give me the continuation of this part of about how to use this pipeline in the receive port.
Thank you so much for the help your blog was so much helpful.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

\\\