Headed to Chicago
Next week I am relocating to Chicago. I’ve already found the Midwest BizTalk User Group and I plan on attending the Chicago meetings. I’ll still be writing BizTalk Server content while attending graduate school.
Liza
Next week I am relocating to Chicago. I’ve already found the Midwest BizTalk User Group and I plan on attending the Chicago meetings. I’ll still be writing BizTalk Server content while attending graduate school.
Liza
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 “<base64Binary>” which contains the
entire array as a base64 encoded string. Not quite what we wanted.
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.
Kurt Claeys posted a whole slew of links for those interested into on WF!
This may require further information. The bottom line is that the tester was unable to reproduce the error conditions you and I have run into. This could mean a couple of things:
1. We’ve finally fixed the problems. The updated support files (see the July 7 post) and the updated instructions (available in the latest doc refresh here: http://www.microsoft.com/downloads/details.aspx?FamilyID=3294ddaf-9f67-409f-a92d-2f6070dc0d1a&displaylang=en) fixed all of the problems. (and I should probably buy some lottery tickets…)
OR
2. There is something else going on, such as an issue with the product editions we use to test the tutorials compared to the editions you use to run the tutorials. If you are using the updated instructions and the updated support files, and you encounter an error, either in the instructions, or an error condition when trying to complete the tutorials, please send me e-mail and include details about the editions and configuration you are using. Adding comments to the blog is great, but it doesn’t provide me a way to work with you directly.
Thanks,
Liza
I’ve decide to update and repost several BizTalk development tips after getting quite a few email questions on mapping. Please keep those questions coming!
I recently needed to find a way to create output nodes conditionally using the BizTalk Server 2006 Mapper. It turns out the process is very straight-forward using a looping functoid and a logical functoid. You can add conditions to a Looping functoid by linking the output of a Looping functoid and a Logical functoid to the same destination record. The destination records are created only when the logical condition is met. In the map shown below I used a Greater Than functoid to create output nodes for items where the quantity used was greater than zero.
Figure 1. Conditional Mapping
Now comes the tricky part! What if you want to know how many items are conditionally created? The Record Count functoid will only generate a count of the number of times a repeating structure (loop) occurs in the inbound message but what we need to know is how many times the repeating structure conditionally occurred. It turns out that none of the standard functoids (even used in combination) will give you the answer but the Scripting functoid using Inline XSLT can!
Figure 2. Scripting Functoid Using Inline XSLT
The XSLT code to create the value for the number of conditionally created records is shown below. I created this by looking closely at the XSLT code generated by the Greater Than functoid and my very limited knowledge of XSLT.
<xsl:variable name=”var:v110“ select=”count(/*[local-name()=’ConsignmentOrder’]/*[local-name()=’item’][@replenish=’R’])“ />
<xsl:attribute name=”TotalLineItems“>
<xsl:value-of select=”$var:v110“ />
</xsl:attribute>
Technorati Tags: BizTalk, BizTalk Server
Mike Taulty, MDE from the UK, has posted a series of 24 screencasts on Workflow Foundation.
Check these out!
Recently I was testing a BizTalk map inside Visual Studios. The input schema was auto generated using the SQL Adapter and the output was a simple text file. I was using a sample file provided to me from a past generation from the schema (or so I thought) to test the map.
1. Schema Validation inside BizTalk DOES NOT validate namespace; at least it doesn’t if there is only one.
2. When you get a strange mapping error with no output, check your namespace!
3. Use extreme caution when typing in the namespace fields when using the SQL Adapter. Evidently in a past test the namespace was typed incorrectly. When the SQL Schema was auto generated, this wrong schema was use to make the sample file I was using.
Recently I was testing a BizTalk map inside Visual Studios. The input schema was auto generated using the SQL Adapter and the output was a simple text file. I was using a sample file provided to me from a past generation from the schema (or so I thought) to test the map.
When I was testing, I keep getting a blank file as output and a strange error. The error was: Native serialization error: Root element is missing.
I had both input and output validation turned on and the input sample file was passing validation. To confirm this, I took the schema and sample file and confirmed it validated using Visual Studios.
Since I was not having much luck testing inside Visual Studios, I decided to set up a send & receive port and test the map through BizTalk to see if I could get different result. This time, I got a subscription not found error.
Odd, since the schema and maps are all deployed. I check the message that was suspended and noticed it was not mapped; my original message was published and suspended.
This could only mean the message type was wrong – somehow. So I took a closer look at the namespace in the sample message. It was slightly off! I corrected the namespace in the sample file and everything worked fine.
Overall, the moral of the story is three fold:
1. Schema Validation inside BizTalk DOES NOT validate name
This gem has been around for a while, but I thought let’s post it for those who don’t know this:
http://www.ssw.com.au/ssw/Standards/Rules/RulestoSuccessfulProjects.aspx
Tired of havng incredibly long xpath statements when using the “xpath” keyword in
your orchestration expression shapes? (They are generally long because of the
xml namespace issues, unless your documents do not use namespaces. When namespaces
are in play, “local-name()” tends to overwhelm your actual path content.)
For BizTalk 2006, we can take advantage of the fact that System.Xml 2.0 added the
ability for documents to supply namespace mappings themselves when doing xpath work
– without the need for manually populating and using a XmlNamespaceManager instance,
as was the case for .Net 1.x. Note that XPathNavigator now (as of .net 2.0)
has a SelectSingleNode method which can accept an implementation of the new IXmlNamespaceManager
interface (which XPathNavigator itself implements.) This means that the ‘xmlns:someprefix=someuri’
declarations in your instance document can actually be used automatically, such that
your xpaths can use the same prefixes when issuing a select. .Net 1.x had no such
mechanism.
So, in whatever “utility” class you have sitting around to help you out when doing
orchestration work, add the following static method. (I generally put such things
outside of a namespace – that way they are a bit more concise inside the orchestration
expression editor.) In high-performance scenarios, may want to measure the performance
of this approach vs. the built-in xpath keyword. Recall that messages can be
passed as XmlDocument instances, so your expression window might have: myString =
XmlUtility.GetXPathStringResult(myMessage,”/spf:someparent/spf:somechild”);
public static string GetXPathStringResult(
XmlDocument document,
string xpath)
{
XPathNavigator nav = document.CreateNavigator();
// (so namespace mappings are in scope when we select)
nav.MoveToChild(XPathNodeType.Element);
XPathNavigator node = nav.SelectSingleNode(xpath, nav);
return node.Value;
}