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();
} } 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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: BizTalk, BTS