Processing Binary Documents Through BizTalk Via Web Services

Just finishing up a two-week BizTalk Proof of Concept where I demonstrated an easier way to manage B2B interactions between a large insurance company and their vendors. This post is focused on one part of the solution that accepts binary messages via web services, and uses BizTalk to extract the message and send to SharePoint.

Instead of using DIME or MTOM, this company exposes a web service where the vendor puts a binary blob into a web service message element. So how did I match this requirement? First, I started with the XML schema for the service interface. Instead of holding a binary node, my DocumentContent node holds a string (base64).

The most important step came next. How do you actually turn this string value back into a binary format to be consumed by BizTalk? I created a class (referencing Microsoft.XLANGs.BaseTypes) containing an implementation of the IStreamFactory interface. The class constructor takes in the base64 string and saves it into a member variable. Then, I implement the required CreateStream method which takes my value and returns a stream of bytes. CreateStream is used when inflating the message part to be sent to BizTalk. The entire class looks like this:

/// <summary>
/// Class which implements XLANG IStreamFactory and lets us define any content
/// to turn into a message. In this case, a string is converted back to binary format
/// and returned in the stream.
/// </summary>
public class MyStreamFactory : IStreamFactory
{
private string messageContent;

public MyStreamFactory(string inMessageContent)
{
messageContent = inMessageContent;
}
#region IStreamFactory Members
public System.IO.Stream CreateStream()
{
byte[] messageBytes = Convert.FromBase64String(messageContent);

return new System.IO.MemoryStream(messageBytes);
}

#endregion
}

The next step was to create an object called from my orchestration that would take this string in, and return the required XLANGMessage back. I created a simple method which takes the inbound string and creates an XLANGMessage using the StreamFactory created above. That class looks like this:

/// <summary>
/// Method to call to generate XLANG message
/// </summary>
public class MyMessageCreator
{
public void CreateMyMessage(XLANGMessage outMessage, string binaryStringMessage)
{
outMessage[0].LoadFrom(new MyStreamFactory(binaryStringMessage));
}
}
Note that I'm setting the first message part of outMessage and using the LoadFrom method.

Back in my orchestration, I have an atomic scope within which I include a variable of type MyMessageCreator. I created a message of type System.Xml.XmlDocument to hold the binary attachment. Remember that a message of this type can hold *anything* as long as you don't try and validate it or do XPath on it. So this will be the message I pass into the CreateMyMessage method as the output parameter. The message assignment shape's code looks like this:

//dummy content setup
VendorMessageDocument_Attach = VendorMessageDocument_Response;

messageCreator = new Customer.POC.FraudDetection.Helper.MyMessageCreator();
messageCreator.CreateMyMessage(VendorMessageDocument_Attach, VendorMessageDocument_Response.DocumentContent);

As you see from the top line, I had to set my "binary document" message equal to something else, just to instantiate it. That value will get overwritten by the subsequent call to CreateMyMessage.

So, after this part of the orchestration, I now have a valid BizTalk message with which to send to a port, which in my case, is a SharePoint library. What I haven't shown yet is HOW to send this document to BizTalk the first place. I exposed this orchestration as a web service, first of all. After referencing this service from my ASP.NET page, I created an instance of the service class, the input document class, and went about taking the selected binary file (Word doc, PDF, Excel, whatever) and adding it to that document message. My code is as follows:

BinaryReader r = new BinaryReader(docUpload.FileContent);
byte[] docBytes = r.ReadBytes(Convert.ToInt32(r.BaseStream.Length));
string convertedText = Convert.ToBase64String(docBytes);
r.Close();
//add this now-formatted base64 string to the web service message payload
doc.DocumentContent = convertedText;

I submit that message, and we're on our way! So as I've shown, you can accept random binary content within a message payload itself (sans attachment), create a valid BizTalk message which contains that binary content, and send it out. Sweet. Now I could easily enhance this by accepting binary content vs. strings, or doing the processing in a pipeline vs. the orchestration. Maybe later ;)

Technorati Tags: BizTalk