Creating Multi-Part Messages in BizTalk

Link. May 1, 2008. Comments [0]. Posted in: BizTalk

Last year I wrote an entry about adding arbitrary binary attachments to a Multi-Part message in BizTalk 2006 using a helper C# component. That entry has been fairly popular (as far as BizTalk posts go, which is not usually much!), and I occasionally get questions about it.

The sample uses a bit of clever code to insert arbitrary attachments into an existing XLANGMessage instance during construction. However, it's not very clear that this is actually a supported scenario and so there's always a chance it might get you into trouble.

I recently thought of another way, possibly much better supported to accomplish the same in BizTalk 2006, though with a little performance hit: Use the Invoke Pipelines feature in BizTalk 2006 Orchestrations.

Basically, the idea would be to create a custom pipeline component (depending on what you need it could be a regular encoding/pre-assemble or an assembler component), generate a new multi-part message in it, and return that to the orchestration.

I haven't tried it yet, but I think it should work.

Vimperator and Firefox 3.0

Link. April 30, 2008. Comments [0]. Posted in: Tools

Just so that I know where to find them (as I always forget):

You can find Vimperator 0.6 builds that work with the Firefox 3.0 betas here: http://www.calmar.ws/firefox/vimperator/

They are updated every so often, so it's useful to keep checking them. I've been using them a few weeks now and it's been working mostly fine!

BizTalk 2006, MSMQ and BizTalk 2002

Link. April 28, 2008. Comments [0]. Posted in: BizTalk

A little over a year ago I posted an entry about a new feature included in the MSMQ Send Adapter in BizTalk 2006 which provided a way to send messages through MSMQ from BizTalk to legacy applications that required the message contents to be formatted using the ActiveXFormatter, or that simply used the old COM-based MSMQ API.

However, I didn't mentioned anything about how to enable the opposite scenario: How to receive and parse a text message in BizTalk 2006 coming from one of those legacy applications. Someone recently asked about this on the BizTalk Newsgroup and, as It turns out, BizTalk Server 2002 happens to fall in this category as well.

Fortunately, this scenario is a lot simpler, if we assume that the contents of the message will be plain text (say, some string content or XML). The ActiveX message serialization rules dictate that a message with a BodyType of String will simply be serialized on the wire as a set of bytes encoded using UCS-2 (UTF-16LE), without a Byte Order Mark (BOM).

BizTalk can parse UTF-16 contents without problems, but without a BOM, the standard disassemblers can't figure out the encoding of the message on it's own.

Fortunately, most of the time you can work around this by setting the message Charset before parsing (for example using my own FixEncoding pipeline component).

Xubuntu 8.04 Installed

Link. April 26, 2008. Comments [2]. Posted in: Linux

Ubuntu 8.04 (Hardy Heron) came out this week, and I downloaded it right away via torrent. I decided to go this time with Xubuntu, which uses XFCE as the desktop environment instead of the regular Gnome or KDE based editions.

Xubuntu804

I had already fooled around with XFCE before and found it to be an excellent desktop environment overall, and much more lightweight than both Gnome and KDE. I was also using Xubuntu 7.10 already on a virtual machine on my Vista box using Virtual Box [1] and it worked very well for my needs (which I admit are fairly basic).

As expected, installation went very well. The only problem I had during installation was that my data drive (a partition I mount my /home in) ended up getting formatted accidentally. I should've paid more attention during partitioning! Fortunately, there was nothing there that was irreplaceable.

After installation, I proceeded to do some tweaking and customization, and enabled the ATI restricted X11 driver using Driver Manager. This time, it worked flawlessly right out of the box, and suspend seems to be working correctly without having to fool around with it at all.

I then went ahead and installed some of the tools I use more often on Linux, like Vim, gnome-terminal, tofromdos and all the samba tools. I now have to install ruby, mono, Open Office (probably), Virtual Box and a few others, but those can wait a bit, as the Canonical servers were still getting hammered pretty hard yesterday. They seem a lot better today, so maybe I'll get some of that installed later on.

Overall, I am very pleased with the experience so far!

[1] I turned to Virtual Box for a couple of reasons: It runs Linux very nicely, unlike Virtual PC, which just sucks at that. I had also been using Virtual Box on a Linux host, and worked very nicely there as well (and seamless mode for Windows-based guests is very nice!).

Registering Null Adapter on 64-Bit Machines

Link. April 24, 2008. Comments [0]. Posted in: BizTalk

Shashikant Raina was kind enough to share with me an issue he ran into while trying my /dev/null Adapter for BizTalk Server on a 64-bit machine:

After creating the adapter registry keys using the included .reg file, he noticed that the adapter would not appear listed in the BizTalk Administration Console when trying to add the adapter to BizTalk.

Here's how Sashikant fixed it:

On 64 bit machine, when you simply click on a registry key file (i.e NullAdapter.reg) it creates entries in default registry editor on that machine. When you then go to Biztalk admin and try to add Null adapter, you can't see it is an option from list of available adapters to add.
Reason, bring that the entries were created in the wrong registry editor (64 bit). To get the correct registry entries, run this registry file
using regedit.exe located in \Windows\SysWOW64 on the 64 bit machine.
This will create Null adapter entries in 32 bit editor. You can then go to Biztalk admin and add the null adapter.

So if this happens to you, just make sure the registry entries are imported into the right place!

Thanks Shashikant!

MVP Summit 2008

Link. April 11, 2008. Comments [0]. Posted in: Personal

Provided the American Airlines problems from this week get sorted out, I'll be attending the MVP Summit again this year. I'll be arriving Sunday pretty late but will be staying until Friday.

If anyone wants to meet, chat, or just say Hi, send me an email (tomas at winterdom.com) or ping me via twitter.

Generating files with PowerShell

Link. April 9, 2008. Comments [0]. Posted in: PowerShell

Yesterday I needed to generate a bunch of small files to use as input for testing, as I needed to reproduce a bug I was tracking down. More to the point, I needed to generate 2000 files of size 781 bytes.

Update: I screwed up the code snippets on my first attempt. Fixed now!

Naturally, I turned to PowerShell and whipped this script:

$fc = new-object string ('a', 781)
1..2000 | %{ [io.file]::WriteAllText("$(pwd)\$_.txt", $fc) }

Is this the only way to do it? Certainly no, but a couple of things are worth mentioning about my specific solution. A savvy reader might ask: Why didn't you just use the redirection operator instead?

1..2000 | %{ $fc > "$_.txt" }

That is indeed shorter, but has one major drawback for my problem: The redirection operator when writing to files defaults to using UTF-16LE encoding, which meant my files would come out the wrong size.

Now, the redirection operator in this case is nothing more than a way to implicitly call the out-file cmdlet, which does provide a way to select the encoding:

1..2000 | %{ $fc | out-file "$_.txt" -enc ascii }

This is much better,  but, unfortunately, still screws up the file size because it will add a CR LF pair at the end. And it isn't remarkably shorter than my original solution using File::WriteAllText().

Async Pipelines and PipelineReader<T> Issues

Link. April 7, 2008. Comments [0]. Posted in: .NET | PowerShell

I've been spending some time this week coding some changes to a custom PowerShell PSHost for an application. One of the changes I wanted to experiment with was changing the code that executed commands so that it used Pipeline.InvokeAsync() instead of Pipeline.Invoke().

There are a couple of things that need to be handled different in this case: How you process the results from the pipeline and how you handle errors. I'll concentrate on the first one, as it is the one that caused me a bit of trouble to get right.

To process the results from an asynchronous pipeline invocation, you need to use a PipelineReader<PSObject> object, which is what the Pipeline.Output property returns. This allows you to read objects generated by the pipeline execution as they are coming out (i.e. as soon as they are available) instead of waiting until the entire pipeline has executed to grab the results, so the idea is pretty nifty.

Unfortunately, the documentation on how to use this object correctly isn't very good. For example, you can't rely on the Count or IsOpen properties as boundary checks to detect how many items to attempt to read. In particular, the Count property isn't reliable if you're using Pipeline.InvokeAsync() because it only represents how many objects are currently available in the reader, not the total count of objects returned by the pipeline (this is natural once you realize it, but still).

Instead, you should really rely on the EndOfPipeline property of PipelineReader<T> to detect when you've reached the end of the object stream generated by the pipeline execution.

The second issue that's not very obvious is that when you use Pipeline.Invoke(), but you don't need to feed inputs to the command, then the pipeline won't really start executing until you close the PipelineWriter object returned by Pipeline.Input. If you don't do this, then PipelineReader.Read() will simply block forever.

Phantom Objects

The one nasty issue I did run is what appears to be a synchronization issue inside PipelineReader<T> itself. In my original attempt to use Pipeline.InvokeAsync(), I started getting some weird results: Ghost objects were coming out of the reader.

Ghost objects?

Pretty much, yes. Let's say I executed an "ls" command on my pipeline that should return 8 items. Sometimes, I'd indeed get the expected 8 items out of the pipeline before EndOfPipeline changed to true. Other times, however, I'd see 9 items come out of it.

The last item was a "ghost" object that was empty: a PSCustomObject with no properties at all. Where was it coming from?

The only good thing about this was that if it appeared at all, it always did it as the last place in the pipeline. This gave me a clue: Could this be a marker object inserted internally by PowerShell into the object stream to mark the end of the pipeline? It sure looked like some kind of null value.

. It is, in fact, AutomationNull.Value, which, although defined in System.Management.Automation.Internal, is a public type/property.

The reason I say this problem is a synchronization issue is that, for the user of PipelineReader<T>, the use of this marker object should've been transparent. Instead, it is a leaking abstraction that sometimes (and just sometimes!) gets exposed and returned from PipelineReader.Read() when it should never happen!

In the end, I ended up rewriting my code like this to work around this problem:

PipelineReader<PSObject> results = pipeline.Output;
while ( !results.EndOfPipeline ) {
   PSObject obj = results.Read();
   // check that the object returned isn't
   // $null, signaling the end of the pipeline
   if ( obj != AutomationNull.Value )
      // do something with the object
}

PipelineTesting v1.1.2.0

Link. April 5, 2008. Comments [0]. Posted in: BizTalk

I've just uploaded a new version of my PipelineTesting library. This one contains just a few minor modifications: A few improved unit tests, and new methods to make it easier to create multi-part messages to use as pipeline inputs.

Here's an example of the last one:

IBaseMessage message = MessageHelper.Create(
   "<body>This is the body part (part1)</body>",
   "<body>This is the part2</body>",
   "<body>This is the part3</body>"
);
Assert.AreEqual(3, message.PartCount);

The new MessageHelper.Create() method takes a params array of strings as argument. Each one will get loaded as a separate message part, with the first one being marked as the body part. There's also a second overload which takes a params array of Stream objects.

As usual, you can download the code from here: PipelineTesting.zip.

About

Tomas Restrepo is co-founder of devdeo. His interests include .NET, Connected Systems, PowerShell and, lately, dynamic programming languages. More...

email: tomas@winterdom.com
msn: tomasr@passport.com
twitter: tomas_restrepo

Technorati Profile

devdeo logo

View my profile on LinkedIn

MVP logo

Syndicate

Ads


Links

Categories

Statistics

Total Posts: 1006
This Year: 76
This Month: 7
This Week: 0
Comments: 771

Blogroll

Post Archive

Other

Copyright © 2002-2008, Tomas Restrepo.

Powered by: newtelligence dasBlog 1.9.7174.0

Sign In