Nigel B
Nigel B

Reputation: 3597

Biztalk 2010 Custom Pipeline Component returns binary

I have created a custom pipeline component which transforms a complex excel spreadsheet to XML. The transformation works fine and I can write out the data to check. However when I assign this data to the BodyPart.Data part of the inMsg or a new message I always get a routing failure. When I look at the message in the admin console it appears that the body contains binary data (I presume the original excel) rather than the XML I have assigned - see screen shot below. I have followed numerous tutorials and many different ways of doing this but always get the same result.

Binary Returned

My current code is:

public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
    {


        //make sure we have something
        if (inmsg == null || inmsg.BodyPart == null || inmsg.BodyPart.Data == null)
        {
            throw new ArgumentNullException("inmsg");
        }

        IBaseMessagePart bodyPart = inmsg.BodyPart;

        //create a temporary directory
        const string tempDir = @"C:\test\excel";
        if (!Directory.Exists(tempDir))
        {
            Directory.CreateDirectory(tempDir);
        }

        //get the input filename
        string inputFileName = Convert.ToString(inmsg.Context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties"));


        swTemp.WriteLine("inputFileName: " + inputFileName);

        //set path to write excel file
        string excelPath = tempDir + @"\" + Path.GetFileName(inputFileName);
        swTemp.WriteLine("excelPath: " + excelPath);

        //write the excel file to a temporary folder  
        bodyPart = inmsg.BodyPart;
        Stream inboundStream = bodyPart.GetOriginalDataStream();
        Stream outFile = File.Create(excelPath);
        inboundStream.CopyTo(outFile);
        outFile.Close();

        //process excel file to return XML
        var spreadsheet = new SpreadSheet();
        string strXmlOut = spreadsheet.ProcessWorkbook(excelPath);

        //now build an XML doc to hold this data
        XmlDocument xDoc = new XmlDocument();
        xDoc.LoadXml(strXmlOut);

        XmlDocument finalMsg = new XmlDocument();
        XmlElement xEle;
        xEle = finalMsg.CreateElement("ns0", "BizTalk_Test_Amey_Pipeline.textXML",
                                      "http://tempuri.org/INT018_Workbook.xsd");
        finalMsg.AppendChild(xEle);

        finalMsg.FirstChild.InnerXml = xDoc.FirstChild.InnerXml;

        //write xml to memory stream
        swTemp.WriteLine("Write xml to memory stream");
        MemoryStream streamXmlOut = new MemoryStream();
        finalMsg.Save(streamXmlOut);
        streamXmlOut.Position = 0;


        inmsg.BodyPart.Data = streamXmlOut;
        pc.ResourceTracker.AddResource(streamXmlOut);


        return inmsg;
    }

Upvotes: 0

Views: 3211

Answers (2)

Ben Cline
Ben Cline

Reputation: 134

Here is a sample of writing the message back:

    IBaseMessage Microsoft.BizTalk.Component.Interop.IComponent.Execute(IPipelineContext pContext, IBaseMessage pInMsg)
        {
            IBaseMessagePart bodyPart = pInMsg.BodyPart;          

 if (bodyPart != null)
            {      
using (Stream originalStrm = bodyPart.GetOriginalDataStream())
                {
                    byte[] changedMessage = ConvertToBytes(ret);
                    using (Stream strm = new AsciiStream(originalStrm, changedMessage, resManager))
                    {
                        // Setup the custom stream to put it back in the message.
                        bodyPart.Data = strm;
                        pContext.ResourceTracker.AddResource(strm);
                    }
                }
            }
     return pInMsg;
}

The AsciiStream used a method like this to read the stream:

override public int Read(byte[] buffer, int offset, int count)
        {
            int ret = 0;
            int bytesRead = 0;

            byte[] FixedData = this.changedBytes;

            if (FixedData != null)
            {
                bytesRead = count > (FixedData.Length - overallOffset) ? FixedData.Length - overallOffset : count;
                Array.Copy(FixedData, overallOffset, buffer, offset, bytesRead);


                if (FixedData.Length == (bytesRead + overallOffset))
                    this.changedBytes = null;

                // Increment the overall offset.
                overallOffset += bytesRead;
                offset += bytesRead;
                count -= bytesRead;
                ret += bytesRead;
            }

            return ret;
        }

Upvotes: 1

Ben Cline
Ben Cline

Reputation: 134

I would first of all add more logging to your component around the MemoryStream logic - maybe write the file out to the file system so you can make sure the Xml version is correct. You can also attach to the BizTalk process and step through the code for the component which makes debugging a lot easier.

I would try switching the use of MemoryStream to a more basic custom stream that writes the bytes for you. In the BizTalk SDK samples for pipeline components there are some examples for a custom stream. You would have to customize the stream sample so it just writes the stream. I can work on posting an example. So do the additional diagnostics above first.

Thanks,

Upvotes: 1

Related Questions