A question on the public BizTalk newsgroups brought the question of how to add arbitrary binary message parts to a multi-part message in an orchestration and have them be correctly processed by the MIME encoding component (or the SMTP adapter) in BizTalk 2006. By this I mean arbitrary parts (such as the contents of a bynary file) without having it declared as part of the multi-part message type itself.
The first thing the poster turned to was to create a custom .NET component that received the message as an argument and then called AddPart() on it passing a byte[] array as an argument. Unfortunately, this causes the message part to be encoded by BizTalk as an XML document with a single root node "
After looking around for a bit, I found a way to get around this by taking advantage of the IStreamFactory interface: By providing a very simple implementation of this interface, and creating the message part on top of that, we can get around this issue. Here's some sample code illustrating the concept:
public class BinaryStreamFactory : RefCountedBase,
IRefCountedStreamFactory
{
private Stream _stream;
public BinaryStreamFactory(Stream stream)
{
if ( stream == null )
throw new ArgumentNullException("stream");
if ( stream.Position != 0 )
{
stream.Position = 0;
}
_stream = stream;
}
public Stream CreateStream()
{
return _stream;
}
public override void Dispose()
{
_stream.Dispose();
}
} // class BinaryStreamFactory
First we need an implementation of IStreamFactory. In this case, we have a fairly simple implementation that just returns the stream we pass in the constructor. Notice also that we also implement it as a RefCounted object (something that BizTalk also looks for an allows us to ensure we know when to close the stream) using the helper RefCountedBase base class.
Now all we need is to add the part by using this BinaryStreamFactory class:
public static void AttachStream(XLANGMessage message, string partName, Stream stream)
{
if ( message == null )
throw new ArgumentNullException("message");
if ( partName == null )
throw new ArgumentNullException("partName");
if ( stream == null )
throw new ArgumentNullException("stream");
IStreamFactory factory = new BinaryStreamFactory(stream);
message.AddPart(factory, partName);
//
// set the Filename property so that it
// gets correctly recognized in the mail
// reader app when it is received as an attachment
//
XLANGPart part = message[partName];
part.SetPartProperty(typeof(MIME.FileName), partName);
}
I built a simple, yet complete example of how to use it, which can be downloaded from here.
One thing to note, however, is that if you are using the SMTP adapter in BizTalk 2006, it already has some features that might make this whole process easier using the SMTP.Attachments context property. My friend Carlos had an example of this here.