On a recent project, we had to deal with binary messages in BizTalk Server 2004. Specifically, we needed to run a binary message through an orchestration, both receiving it and sending it through messaging ports, as well as passing it to custom .NET components that knew how to manipulate it.

In our case, this was basically a binary compressed (zipped message), which we decided explicitly not to decompress during a pipeline, and instead always keep it in it's original raw form. Handling it wasn't much of a problem for the most part, since you can apply the same trick the RawString class does, but just keeping the contents as a Byte[] instead of a string (implementing it from scratch left as an exercise for the reader).

The only tricky part was getting BizTalk to receive the raw binary message and fire off our orchestration to process it without jumping through too many hoops. Scott Colestock has a great entry on how to receive a RawString on an orchestration, so we obviously turn to that for inspiration. But, even with all the great advice from Scott and both alternatives presented there, it's still quite a bit of work.

Fortunately, working with my friend Gustavo we found out an easier way that didn't involve multipart message types or custom pipelines. It goes like this:

The BizTalk orchestration is setup to receive a message of type XmlDocument, which ensures that the activation subscription for the orchestration does not contain a MessageType-based predicate. Then, we construct a new message declared using our custom .NET class (let's call it BinaryMessage), and initialize it in a Message Assignment shape by calling the new operator to call a constructor, passing the original XmlDocument message as an argument.

Here's were we differ from the other proposed solutions: Our custom constructor takes an XLANGMessage instance as an argument. We figured it wouldn't work at first because the original message in the orchestration was an XmlDocument and not a regular BizTalk message, but it didn't cause a problem. Anyway, since we have the XLANGMessage instance, we could simply get the body part and call RetrieveAs() to get the contents of the message as a Stream and read that into our internal Byte[] array, like this:

public BinaryMessage(XLANGMessage doc)
{
Stream stream = (Stream)doc[0].RetrieveAs(typeof(Stream));
using (stream)
{
MemoryStream tempStream = new MemoryStream();
byte[] buffer = new byte[64*1024];
int bytesRead = 0;
while ( (bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0 )
tempStream.Write(buffer, 0, bytesRead);
Contents = tempStream.ToArray();
}
}

Granted, the solution isn't terribly efficient (since it does involve doing a message copy), but since we're only going to be processing about a couple messages a day, that wasn't a significant concern.

Technorati tags: ,


Tomas Restrepo

Software developer located in Colombia. Sr. PFE at Microsoft.