How can I decompress a gzip file in a custom pipeline

1.1k Views Asked by At

I tried to create a custom BizTalk 2013 R2 (receive or send) pipeline that can unpack a xxx.GZ file that contains some txt files to a send port.

Here is what I have tried until now:

PS. I used .Net's IO GZip classes.

  1. Created a BTS application, configured receive location and send port.

  2. The receive location uses a custom pipeline that I have created, here is my code of the custom pipeline I tried:

        public void Disassemble(IPipelineContext pc, IBaseMessage inmsg)
        {
            IBaseMessagePart bodyPart = inmsg.BodyPart;
    
            if (bodyPart != null)
            {
                Stream originalStream = bodyPart.GetOriginalDataStream();
    
               if (originalStream != null)
                {                     
                    using (GZipStream gZipInputStream = new GZipStream(new MemoryStream(originalStream.ReadByte()), CompressionMode.Decompress))
                    {    
                        MemoryStream memStream = new MemoryStream();
                        byte[] buffer = new Byte[1024];
    
                        int bytesRead = 1024;
                        while (bytesRead != 0)
                        {
                            bytesRead = gZipInputStream.Read(buffer, 0, buffer.Length);
    
                            gZipInputStream.CopyTo(buffer, 0);
                            memStream.Write(buffer, 0, bytesRead);
                        }
    
                        IBaseMessage outMessage;
                        outMessage = pc.GetMessageFactory().CreateMessage();
                        outMessage.AddPart("Body", pc.GetMessageFactory().CreateMessagePart(), true);
                        memStream.Position = 0;
                        outMessage.BodyPart.Data = memStream;
    
                        outMessage.Context = PipelineUtil.CloneMessageContext(inmsg.Context);
    
                        _msgs.Enqueue(outMessage);
    
                        }
                    }   
            }
    
        }
    

This code seems to not work as I want. just send the GZ file without unpacking it to the send port. I use the implemented pipeline in the receive location port. Here is how it work: When BizTalk receive a GZ packed file on its receive location it just send the file to the send port that subscribe on this receive location. It seems like that the pipeline doesn't do any thing to the GZ stream. What it should do is to unpack the GZ file and send all the unpacked files to the send port, this points to a folder where the unpack files need to be placed.

I tried to google with no luck and the samples that exist seems to not work for me.

So can anyone help me or tell what I'm doing wrong in my code. I just want to implementing a C# custom BizTalk 2013 R2(receive or send) pipeline that can unpack a received GZ file, that contains some txt files, to a send port (point to a folder)?

Update:

As the Dissambler version didn't work I created a decode version.

Here is the decode code in the pipeline:

                #region IComponent members
    /// <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 pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
    {
        if (null == pc) throw new ArgumentNullException("pContext", "Pipeline context can not be null");

        if (null == inmsg) throw new ArgumentNullException("pInMsg", "Input message can not be null");

        IBaseMessagePart bodyPart = inmsg.BodyPart;

        if (bodyPart != null)
        {
            GZipStream strm = new GZipStream(bodyPart.GetOriginalDataStream(), CompressionMode.Decompress);
            bodyPart.Data = strm;
            pc.ResourceTracker.AddResource(strm);
        }

        return inmsg;
    }
    #endregion

How can I get correct filename of each file in the GZip file? So when the message is sent to the send port, it should write the file with the correct filename.

1

There are 1 best solutions below

1
Dijkgraaf On

It looks like you implemented the custom pipeline component as a Disassemble stage, it should actually be a Decode stage pipeline component for the following two reasons.

  1. In the disassemble stage you can only ever have one component that executes. That means you then can't also have a flat file, XML or JSON dissasembler executing.
  2. If it is a disassemble stage component you also need to implement a probe to see if the message is recognized, otherwise it won't execute.

See MSDN Receive Pipelines

Decode stage

  • This stage is used for components that decode or decrypt the message.
    • The MIME/SMIME Decoder pipeline component or a custom decoding component should be placed in this stage if the incoming messages need to be decoded from one format to another.
  • This stage takes one message and produces one message.
  • This stage can contain between zero and 255 components.
  • All components in this stage are run.

Disassemble stage

This stage is used for components that parse or disassemble the message.

  • The components within this stage probe the message to see if the format of the message is recognized. Based on the recognition of the format, one of the components disassembles the message.
  • If this stage contains more than one component, only the first component that recognizes the message format is run. If none of the components within the stage recognize the message format, the message processing fails.
  • This stage should include any custom components that implement special behavior to disassemble the message contents.
  • This stage can contain between zero and 255 components. If there are no components in the stage, the message is passed through.

Update: With the update of you question it gets a bit trickier. If you have to split a message into multiple messages, the only stage you can do it in is the Disassemble stage. So you will have to go back to that version and debug it and work out why it does not execute the unzip.

There is a old code sample for a Zip Disassembler UnzipDisassembler - A custom pipeline component for BizTalk Server 2004 which is for a Zip file rather than a Gzip. But it follows the same sort of pattern. What you will also need is a method similar to GetNextEntry to publish a message and then parse the next file. It is at the outmsg creation stage that you can set the context properties such as filename.