Saturday, September 09, 2006

I found 2 links that I want to keep here, for my future reference. If someone else uses them, I ask that they deposit $10,000 in my swiss bank account...(doesn't hurt to ask, right)?

The first one, from David Hurtado's blog, shows how to promote context properties within an orchestration. It also has a link to Jon Flander's blog to show how to do this in a pipeline component (which I believe you could now use inside an orchestration with BizTalk 2006).

The second link is to Jan Eliasen's blog. I've been tearing my hair out because for most of DTD's that I get from customers, when I import them into Visual Studio and use the schema editor, all of the nodes show up at the top level. Jan showed me how to get the schema to show up in VS in a clean, heirarchical way.

Friday, March 03, 2006

BizTalk Pipelines Factoid

I'm sitting in the BizTalk 2006 Deep Dive training in Redmond right now, and the instructor told me some stuff that I don't remember seeing elsewhere. So I'm going to document this for myself and others.

The provided XMLTransmit pipeline will ensure that an incoming document is well formed XML, but it won't validate the document against a schema. In order to validate against a schema, you need to create a pipeline and do one of two things:

  • Drop an XML disassembler component into the pipeline, set the "Validate document structure" property to false, and then drop an XML validator component as well. This will validate the XML document against any schema that is deployed to your host.
  • Drop only an XML disassembler into the pipeline, set the "Validate document structure" property to true, and then add one or more schemas to the "Document schemas" property.

Note that if you use the XML validator component as desribed above, you don't have to specify a schema. However, if you do specify a schema (or schemas) in this component, the pipeline will then validate only against that specific schema (or schemas).

If you do choose to use a port to validate according to a schema, BizTalk 2006 will make it easier. In BTS 2006, pipelines support parameters, and you can override the schema(s) that are used.

BTW, I'm using the word "factoid" in the title because I figure if functoid is a word, than factoid must also be.

Saturday, February 11, 2006

BizTalk Mapper - Looping Tricks

This post is intended to demonstrate 2 ways of using the looping functoid. One is pretty obvious, and the other shows a use for the looping functoid that requires a bit of help from a logical functoid.

Along the way I'll also show how a value mapping functoid works.

I have created 2 schemas intended to represent the status of a previously sent purchase order. POS.xsd is the output from a Line of Business (LOB) application, and PO_Status is intended to be sent to the customer. The LineItem node in POS.xsd and the Product node in POStatus.xsd both repeat 1 to unbounded times. Here's how the map looks:

The red functoid is a String Concatenate functoid, which has 3 inputs - ShipperName, a constant " - ", and ServiceLevel. The DateShipped element is mapped straight across, or "as is".

The turquoise functoids are Greater Than (GT) functoids. The first input you can see on the screen for the upper GT functoid is the QuantityOrdered element, and the second input is "0". This functoid will return true if the value in QuantityOrdered is more than 0. The output of this functoid is mapped into 2 Value Mapping (VM) functoids. A value mapping functoid will return it's second input only if the value of the first input is 0. So the uppermost VM functoid will return its second input (the string "Ordered", which you can't see) if the value in QuantityOrdered is > 0, and that is mapped into GlobalQuantityTypeCode. The second VM functoid will return its second input (QuantityOrdered) if QuantityOrdered is > 0, and that value is mapped into ProductQuantity.

And Here's a sample of the input XML:

<ns0:PurchaseOrderStatus xmlns:ns0="http://Test.POS">
<ShipperName>UPS</ShipperName>
<ServiceLevel>2nd Day</ServiceLevel>
<DateShipped>05/17/2005</DateShipped>
<LineItem>
<ItemNumber>X-12</ItemNumber>
<QuantityOrdered>10</QuantityOrdered>
<QuantityShipped>5</QuantityShipped>
<QuantityBackordered>5</QuantityBackordered>
<QuantityCancelled>0</QuantityCancelled>
</LineItem>
<LineItem>
<ItemNumber>A-24-P</ItemNumber>
<QuantityOrdered>200</QuantityOrdered>
<QuantityShipped>200</QuantityShipped>
<QuantityBackordered>0</QuantityBackordered>
<QuantityCancelled>0</QuantityCancelled>
</LineItem>
<LineItem>
<ItemNumber>T-707F</ItemNumber>
<QuantityOrdered>12</QuantityOrdered>
<QuantityShipped>0</QuantityShipped>
<QuantityBackordered>6</QuantityBackordered>
<QuantityCancelled>6</QuantityCancelled>
</LineItem>
</ns0:PurchaseOrderStatus>

Notice in the Visual Studio output window above that there is an error. This occurred when I tried to test the map you see above. The warning immediately below the error reads in full: "The destination node "GlobalOrderQuantityTypeCode" has multiple inputs but none of its ancestors is connected to a looping functoid."

This error can be easily remedied by adding a looping functoid, which can be found in the Toolbox under Advanced Functoids:

In the image above, you can see that I have added a purple functoid (the Looping functoid) that connects the LineItem node in the source schema with the Product node in the destination schema. But there's still an error. What I've done in effect is to tell BizTalk, for every LineItem in node in a source document, create a Product node in the output document. But I'm going to have to also account for the fact that within 1 Product node in the output, there are possibly multiple OrderStatusQuantity nodes.

Here's another attempt:

I have put another Looping functoid on the map, and connected the QuantityOrdered and QuantityShipped node outputs to it. What does this do? Essentially, it says that whenever you have an input node, create another OrderStatusQuantity node. Well if I'm so clever, why am I still getting an error? Because other functoids that I've explained above say to only create the nodes under OrderStatusQuantity node if the source value is greater than 0. QuantityShipped in the 3rd LineItem in the sample XML is 0, so I'm essentially telling BizTalk to create an OrderStatusQuantity node, but don't create its children. Since the children are required in the schema, I get an error.

Let's try one more time:

Finally! If you look closely at the map, you can see that I've drawn lines from the GT functoids to the OrderStatusQuantity node. This shows a very useful property of logical functoids. If you map the output of a logical functoid to a node, it will act to suppress the production of that node when the output of the logical functoid is false. So the OrderStatusQuantity node will be created if and only if the QuantityOrdered or the QuantityShipped field contains a value greater than 0.

Here's the XML output. Note that in the last Product node, there is only one OrderStatusQuantity:

<ns0:PO_Status xmlns:ns0="http://Test.POStatusOut">
<ShipDate>05/17/2005</ShipDate>
<ShippedVia>UPS - 2nd Day</ShippedVia>
<Product>
<ProductIdentifier>X-12</ProductIdentifier>
<OrderStatusQuantity>
<GlobalOrderQuantityTypeCode>Ordered</GlobalOrderQuantityTypeCode>
<ProductQuantity>10</ProductQuantity>
</OrderStatusQuantity>
<OrderStatusQuantity>
<GlobalOrderQuantityTypeCode>Shipped</GlobalOrderQuantityTypeCode>
<ProductQuantity>5</ProductQuantity>
</OrderStatusQuantity>
</Product>
<Product>
<ProductIdentifier>A-24-P</ProductIdentifier>
<OrderStatusQuantity>
<GlobalOrderQuantityTypeCode>Ordered</GlobalOrderQuantityTypeCode>
<ProductQuantity>200</ProductQuantity>
</OrderStatusQuantity>
<OrderStatusQuantity>
<GlobalOrderQuantityTypeCode>Shipped</GlobalOrderQuantityTypeCode>
<ProductQuantity>200</ProductQuantity>
</OrderStatusQuantity>
</Product>
<Product>
<ProductIdentifier>T-707F</ProductIdentifier>
<OrderStatusQuantity>
<GlobalOrderQuantityTypeCode>Ordered</GlobalOrderQuantityTypeCode>
<ProductQuantity>12</ProductQuantity>
</OrderStatusQuantity>
</Product>
</nso:PO_Status>

Saturday, February 04, 2006

What's My Blog?

I've been reflecting on "what my blog is about". I used to reflect on my life in the same way, but never came to a definite conclusion. So I'm narrowing the focus of my question to just the blog.
:-)

My intention is to write about some technical items that should be easy, but weren't necessarily (at least to me). A lot of what I write might look like it's for beginners, but if it took more than a little research to find it, I think it's worth writing down.

Hopefully you'll either agree, or read someone else's blog.
;-)

Thursday, February 02, 2006

BizTalk 2006 SMTP Adapter

I found a couple of great articles on using the SMTP adapter on Richard Seroter's blog here, and Tomas Restrepo's blog here. What follows are a couple of things that I had to find elsewhere.
For the following examples, I assume you've already created 2 multipart messages EmailIn and EmailOut, each with a body part and an attachment part called Remainder. EmailIn has been used to receive an email using the POP3 adapter (see my previous post), and EmailOut is for sending an email out via SMTP. I also assume that you've at least partly built the EmailOut message, see the 2 links above if you don't know how.

To set the filename for the attachment:
EmailOut.Remainder(MIME.FileName) = "MySpecialTitle.XML";
To set the subject of the outgoing email from the incoming email:
EmailOut(SMTP.Subject) = EmailIn(POP3.Subject);
By the way, these need to be done in a constructor for EmailOut.

To send your email to an address that is to be configured at run-time, assuming that you've managed to get the correct address into the variable emailAddress:
  1. Creating a dyamic port
  2. Create an expression shape
  3. Enter code that looks like this in the expression shape:
    DynamicPort(Microsoft.XLANGs.BaseTypes.Address) = "mailto:" + emailAddress;

It took me a while to figure out how this could work, my guess is that the "mailto:" prefix somehow indicates to BizTalk that it should use SMTP for that port, just as http tells your browser to use port 80.

Hopefully you can extrapolate other things that you might need from the links and these examples.

Tuesday, January 31, 2006

BizTalk 2006 POP3 Adapter

There are a few things that I've learned recently while using the latest BizTalk 2006 beta. I'll start by listing a few things that might help someone who is using the new POP3 Adapter. This information was gathered from other web pages, news groups, and my own experience.

Using the POP3 adapter to receive a message where the XML attachment is all that you care about is about as easy as using any other adapter. I've seen information about this in other places, so I won't copy it here.

To use the POP3 adapter to receive an email with attachments in an orchestration (where the number of attachments is fixed and known) and you intend to have access to all parts of the email:
  1. Create a multipart type in the orchestration, one part for the email body and one for each attachment.
  2. Make each part of the multipart type an XmlDocument, even if the body of the message is not XML. I've seen articles that make me think it might be important for the body part of the multipart type to be created first, although I haven't tested it any other way.
  3. Since Visual Studio will sort the parts of the multipart type by name (although the actual order of the parts in the ODX file is unaffected), I recommend naming the parts something that will maintain the same order, for example "BodyPart" and "Remainder1", "Remainder2", etc.
  4. In the orchestration, to use any of the incoming parts that are XML, you can simply assign that body part to your message (it took me a while to discover that [for my purposes, anyway] XmlDocument is assignment compatible with any message that is of an XML schema type).
When I first tried receiving a POP3 message in an orchestration, I received the following error message:
Multi-part message 'EmailIn' has body part '{AE9F5DD0-CE12-49C3-B9B3-577D3B134EBB}', expected body part '{3FB96D26-27B3-44A1-9606-CFBEA88A668D}.
When I created the receive port, I had left the body part index set to 0 in the receive location. My thinking was that since I wasn't going to select just a part of the message, I could leave it at the default. Well, my thinking was wrong -- the error went away when I changed the body part index to 1, and I was able to receive the email in the orchestration.

2/9/2006 - There's more on the POP3 adapter from Richard Seroter here.