Some of my colleagues asked me to help them out with a really hairy problem today. Their project involved the receipt of EDIFact files by email. The emails were being saved on the file system as .eml files which were then picked up and processed by BizTalk. The email would contain the message body which was of content type text/plain and the EDI message which was an attachment of content type application/octet-stream.
Everything worked fine on development when they were working with eml files that were created by the developers, but when they tried to test the solution against an instance of a real eml file sent from one of the trading partners the receive pipeline failed with the following error – “A body part or a part with the same name has already been added to this message. A message can have only one body part and part names must be unique.”
Inspecting their pipeline showed that they were making use of a MIME/SMIME decoder component (they were selecting the body part by type application/octet-stream rather than index), an EDI disassembler component, an EDI Party Resolution component, and a whole lot more custom components.
My initial gut feel was that the problem must lie in the disassemble stage so I got an example message off them and whipped up a receive pipeline containing the MIME/SMIME decoder component and the EDI Disassembler component, both with exactly the same settings as they had. As soon as I ran the file through my pipeline I saw the same error. To isolate the issue I tried to remove the EDI Disassembler from the pipeline and the error was no long encountered.
I opened the eml file in notepad and noticed that the content-description for the body of the message had a value of body (see below for an excerpt). I changed the value to body1 and tried playing the message through my pipeline and this time it worked!
I didn’t have a copy of reflector handy so I couldn’t quite inspect what the MIME/SMIME decoder or the EDI Disassembler component were doing, but my educated guess was that the MIME/SMIME decoder component would name each message part according to the content-description in the eml file, and that when the EDI Disassembler disassembled the raw EDIFact into XML and was trying to add it to the message it was setting the part name to body which resulted in a clash because one of the non-body parts was already name body.
My colleagues asked me to whip up a quick workaround for them which would ensure that if any of the non-body parts had a name of body that it would rename them to something else. Due to time constraints I largely based my code off the ArbitraryXPathPropertyHandler pipeline component which is a Microsoft sample that can be found in C:\Program Files (x86)\Microsoft BizTalk Server 2010\SDK\Samples\Pipelines\ArbitraryXPathPropertyHandler on any BizTalk 2010 dev PC.
The execute method of my pipeline component looks like the below. Note that it creates a new instance of a message and copies the context over (it does so by reference here, you can always do a manual copy of the context properties if you want to but since we are not manipulating the message whatsoever it isn’t entirely necessary), creates a new message part which points at a stream derived from the original message’s body part (again you could clone the stream rather than use the original stream if you wanted to), and then calls the CopyMessageParts method passing in the original message as the source, the copied message as the target, and the copied body part (the extraction of the body part in the execute message is somewhat unnecessary but since this was a quick I didn’t bother to vary from the Microsoft sample too much). It then returns the copied message to the remaining components in the pipeline.
The CopyMessageParts method looks like the below. It literates through each of the message parts in the source message and copies them over to the target (again, you could clone the message part data instead of copying it over by reference if you want to). If however the name of a non-body part message is body then it will replace the part name with oldBody plus a GUID.
Placing this pipeline component in the decode stage after the MIME/SMIME decoder component now allows the EDI Disassembler to process successfully and work around the problem. This pipeline component might not be 100% as I did this as a quick and dirty exercise, and my colleagues will most likely clean it up but I hope this helps others who bump into the same issue to identify their problem and come up with an appropriate workaround as well.