locked
How should I decode Base64 encoded XML node to a file ? RRS feed

  • Question

  • If I have an Inbound XML File in the following format 

    <DownloadReports xmlns="https:EXAMPLE.COM">
    
    <NGSDownloadReportsResult>
    BASE64ENCODEDFILE
    </NGSDownloadReportsResult>
    
    </DownloadReports>

    How should I pick the NGSDownloadReports node and save the decoded Base64 String as file ? I am new to BizTalk, sorry for noob questions.


    • Edited by svemaraju Tuesday, August 20, 2013 6:09 PM
    Monday, August 19, 2013 7:38 PM

Answers

  • Using the XmlReader, you would advance the Reader until it's on the NGDDownloadReports node, then MoveToContent.

    XmlReader is a forward only reader so it doesn't really support 'search', you move the pointer until you land on the node you're looking for.

    You can take a shortcut by using the ReadToDescendant method.

    Monday, August 19, 2013 9:05 PM
    Moderator

All replies

  • I am thinking of using a Orchestration. Use XPATH from my schema and use a external helper class to convert it into a string and assigned it to a message of the type System.String or System.XML.XMLDocument
    • Edited by svemaraju Monday, August 19, 2013 8:11 PM
    Monday, August 19, 2013 7:41 PM
  • Is base64encodedfile is an xml ? can you please explain your scenario is more detail?



    If this answers your question please mark it accordingly. If this post is helpful, please vote as helpful.

    Monday, August 19, 2013 7:56 PM
  • Base64EncodedFile is a Base64 Binary value that represents a file.

    In my scenario I am uploading a file (can be any format) by converting it into its base64 representation to a webservice, I get a response from the webservice and within the response I am expecting as a base64 value inside the xml node (as shown above).

    I need to decode this base64 value to extract the file I need.

    Note: My outbound message needs to contain converted base64 representation of the file (not the XML with base64 value inside it).



    • Edited by svemaraju Monday, August 19, 2013 8:12 PM
    Monday, August 19, 2013 8:03 PM
  • So, there's no way to do this without some code.

    There are several facilities in the .Net Framework that will perform the decoding so which you choose will depend on where you perform this operation.

    If all you care about is what's base64 encoded, and not much if anything from the original message, I would do the conversion in a custom pipeline component.

    You can create an XmlReader of the incoming Stream, then use XmlReader's ReadContextAsBase64 to convert the encoded content into the comparable byte array, then copy the array to a second Stream, MemoryStream for example, and use that as the content of the returned BizTalk Message.

    Once that's done you can simple route to message to a FILE Send port and you'll have the decoded content.

    Here's a good place to start: http://msdn.microsoft.com/en-us/library/aa548050.aspx

    And the Wizard: http://btsplcw.codeplex.com/

    Monday, August 19, 2013 8:17 PM
    Moderator
  • How do I choose the NGSDownloadReports node inside my custom receive pipeline ?

    • Edited by svemaraju Monday, August 19, 2013 8:52 PM
    Monday, August 19, 2013 8:19 PM
  • Using the XmlReader, you would advance the Reader until it's on the NGDDownloadReports node, then MoveToContent.

    XmlReader is a forward only reader so it doesn't really support 'search', you move the pointer until you land on the node you're looking for.

    You can take a shortcut by using the ReadToDescendant method.

    Monday, August 19, 2013 9:05 PM
    Moderator
  • You would need to write code. If I understand correctly, you will get the Base64 encoded file in the Web Service response, you need to decode it and write it to a file.

    Well one way would be

    1. Use the RawStringFormatter and create a mulit-part message type in your orchestration. The bodypart in this message would be of type RawString.
    2. Create a .Net Helper which will accept the XLANGMessage as a parameter.
    3. In the .Net helper, use XMLDocument to get to the node NGSDownloadReports and you will get the Base64 encoded data as a byte[]
    4. Use the System.Text.Convert.FromBase64String to decode and assign it to a "RawStringType".
    5. In your orchestration have a message construct shape with the assign shape and directly assign the output of your helper to an instance of the multi-part message type created.
    6. Use the File Adapter to send the message. You may give it a filename by assigning the (FILE.ReceivedFilename) property on the message and using the %SourceFilename% macro on the send port.

    Regards.

    PS: the RawStringFormatter is available under BizTalk SDL Samples and you can GAC it to Samples.BizTalk.XlangCustomFormatters.RawString

    • Edited by Shankycheil Tuesday, August 20, 2013 5:41 AM RawStringFormatter Sample Reference
    Tuesday, August 20, 2013 5:39 AM
  • What am I doing wrong here ? I am getting an empty xml instead of selecting my node

          public static IBaseMessage GetNewMessage(IPipelineContext pc, Stream body, string messageType)
            {
                if (pc == null || body == null || string.IsNullOrWhiteSpace(messageType))
                    throw new ArgumentNullException();
                IBaseMessage newMessage = pc.GetMessageFactory().CreateMessage();
                IBaseMessagePart messagePart = pc.GetMessageFactory().CreateMessagePart();
                newMessage.AddPart("Body", messagePart, true);
                newMessage.BodyPart.Data = body;
                if (String.IsNullOrWhiteSpace(messageType) == false)
                    newMessage.Context.Promote("MessageType", "http://schemas.microsoft.com/BizTalk/2003/system-properties", messageType);
                return newMessage;
            }
    
           
            public void Disassemble(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
            {
                XmlReader reader = XmlReader.Create(inmsg.BodyPart.GetOriginalDataStream());
                if (reader.MoveToContent() == XmlNodeType.Element && reader.Name == "NGSDownloadReportsResult")
                {
                    string str = reader.ReadString();
                    long length = str.Length;
                    byte[] data = System.Text.Encoding.UTF8.GetBytes(str);
                    MemoryStream stream = new MemoryStream();
                    stream.Write(data,0,data.Length);
                    pc.ResourceTracker.AddResource(stream);
                    string messageType = "https://XYZ";
                    inmsg = GetNewMessage(pc, stream,messageType);
                }
                _msgs.Enqueue(inmsg);
            }


    • Edited by svemaraju Tuesday, August 20, 2013 6:06 PM
    Tuesday, August 20, 2013 6:05 PM
  • Stream originalstream = inmsg.BodyPart.GetOriginalDataStream();
                originalstream.Position = 0;
                XmlReader reader = XmlReader.Create(originalstream);
                reader.ReadToFollowing("NGSDownloadReportsResult");
                string str = reader.ReadElementContentAsString();
    Solved it.
    Tuesday, August 20, 2013 7:45 PM
  • Super, but it looks like that only half the solution.  You still need to decode the string from Base64.  That's where XmlReader's ReadContentAsBase64 comes in handy.
    Tuesday, August 20, 2013 8:11 PM
    Moderator
  • In your first post you provided the input xml as:

    <DownloadReports xmlns="https:EXAMPLE.COM">
    	<NGSDownloadReportsResult>
    		BASE64ENCODEDFILE
    	</NGSDownloadReportsResult>
    </DownloadReports>

    However in the last post that you have posted for you have Disassemble method as follows:

            public void Disassemble(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
            {
                XmlReader reader = XmlReader.Create(inmsg.BodyPart.GetOriginalDataStream());
                if (reader.MoveToContent() == XmlNodeType.Element && reader.Name == "NGSDownloadReportsResult")
                {
                    string str = reader.ReadString();
                    long length = str.Length;
                    byte[] data = System.Text.Encoding.UTF8.GetBytes(str);
                    MemoryStream stream = new MemoryStream();
                    stream.Write(data,0,data.Length);
                    pc.ResourceTracker.AddResource(stream);
                    string messageType = "https://XYZ";
                    inmsg = GetNewMessage(pc, stream,messageType);
                }
                _msgs.Enqueue(inmsg);
            }
    On the first look I see that in your xml your root node is "DownloadReports" however,  in your method you are matching for "NGSDownloadReportsResult"


    Can you please make this change and see if it works?


    If this answers your question please mark it accordingly. If this post is helpful, please vote as helpful.

    Tuesday, August 20, 2013 8:42 PM
  • Thanks, This is how I did it

    byte[] data = Convert.FromBase64String(str);
    Now I need to unzip those bytes and extract two files .. I am planning to use ICSharpCode to unzip ... but, how do I set the inmsg to return two different messages ?

    • Edited by svemaraju Tuesday, August 20, 2013 10:51 PM
    Tuesday, August 20, 2013 8:44 PM