Wednesday, March 25, 2009

Hi all

Someone at the online general BizTalk forum asked a question about combining two messages in a map. Now, he all ready knew about creating the map from inside an orchestration, but let me just quickly summon up for those not knowing this. If you have two messages inside an orchestration that you need to merge into one message in a map, what you do is that you drag a transformation shape into your orchestration like this:

DualInputOrchestration

In my example, I have a parallel convoy to get the two input messages into my orchestration. I then have two different ways of combining the two input messages into one output, and each is then output.

Anyway, after the transform shape is dragged onto the orchestration designer, you double-click on it to choose input and output messages like this:

DualInputCreateMap

You can add as many source messages as you want – I have chosen two messages. Make sure the checkbox at the bottom is selected. Then click “OK” and the mapper will open up. It will have created an input schema for you, which is basically a root node that wraps the selected source messages. At runtime, the orchestration engine will take your messages and wrap them to match this schema and use that as input for the map.

In my case, I have these two schemas:

DualInputSchemaHouseBill 

and

DualInputSchemaWayBill

My output schema looks like this:

DualInputSchemaOutput

The automatically generated map looks like this:

DualInputGeneratedMap

As you can see, the destination schema is just like my output schema, but the input schema wraps my two input schemas into one schema.

So… I have just briefly explained how two create the map that can combine two messages into one. Now for the functionality inside the map.

Most maps like this can be mapped like any other complex input schema. But sometimes you need to somehow merge elements inside the source messages into one element/record in the destination. This automatically becomes different, because the values will appear in different parts of the input tree.

The requirement that was expressed by the person asking the question in the online forum was that these two inputs:

DualInputSchemaHouseBillExample

and

DualInputSchemaWayBillExample

and combine them into this:

DualInputSchemaOutputExample

So basically, there is a key that is needed to combine records in the two inputs. My schemas above are my own schemas that roughly look like the schema that was in use in the forum.

My first map that will solve the given problem looks like this:

DualInputMapFunctoids

Quite simple, actually. I use the looping functoid to create the right number of output elements, and I use the iteration and index functoids to get the corresponding values from the WayBill part of the source schema. The index funtoid can take a lot of inputs. In my case the path to the element is always the first until the vey last step, where I need to use the output of the iteration functoid. So I have only two inputs: The element that loops and the index of the parent of this element because that is the only place where I need to go to a specific element.

This works very nicely, but it has one serious drawback (and a minor one, which I will get back to later): It requires that the elements appear in the exact same order in both inputs. If this restriction can be proven valid, then this is my favorite solution, since I am a fan of using the built-in functoids over scripting functoids and custom XSLT if at all possible. I didn’t ask the person who had the issue if this restriction is valid, but thought I’d try another approach that will work around this just in case. This requires some XSLT, unfortunately, and the map looks like this:

DualInputMapXSLT

Quite simple, really :-) The scripting functoid takes care of the job for me. It is an “Inline XSLT Call Template” functoid and the script goes like this:

<xsl:template name="BuildOutput">
<xsl:param name="ID" />
<xsl:element name="Output">
<xsl:element name="Number"><xsl:value-of select="$ID" /></xsl:element>
<xsl:element name="OriginPortId"><xsl:value-of select="/*[local-name()='Root' and namespace-uri()='http://schemas.microsoft.com/BizTalk/2003/aggschema']/*[local-name()='InputMessagePart_0' and namespace-uri()='']/*[local-name()='HousebillRoot' and namespace-uri()='http://DualInput.DualSchemaHouseBillInput']/*[local-name()='HouseBillsNode' and namespace-uri()=''][HouseBillNo = $ID]/*[local-name()='OriginPortId' and namespace-uri()='']" /></xsl:element>
<xsl:element name="ShippingAddress"><xsl:value-of select="/*[local-name()='Root' and namespace-uri()='http://schemas.microsoft.com/BizTalk/2003/aggschema']/*[local-name()='InputMessagePart_1' and namespace-uri()='']/*[local-name()='WayBillRoot' and namespace-uri()='http://DualInput.DualSchemaWayBillInput']/*[local-name()='WayBillInfo' and namespace-uri()=''][WayBillNo = $ID]/*[local-name()='ShippingAddress' and namespace-uri()='']" /></xsl:element>
<xsl:element name="ContainerAddress"><xsl:value-of select="/*[local-name()='Root' and namespace-uri()='http://schemas.microsoft.com/BizTalk/2003/aggschema']/*[local-name()='InputMessagePart_1' and namespace-uri()='']/*[local-name()='WayBillRoot' and namespace-uri()='http://DualInput.DualSchemaWayBillInput']/*[local-name()='WayBillInfo' and namespace-uri()=''][WayBillNo = $ID]/*[local-name()='ContainerAddress' and namespace-uri()='']" /></xsl:element>
</xsl:element>
</xsl:template>

Now this looks complex, but really it isn’t. Let me try to shorten it for you to be more readable:

<xsl:template name="BuildOutput">
<xsl:param name="ID" />
<xsl:element name="Output">
<xsl:element name="Number"><xsl:value-of select="$ID" /></xsl:element>
<xsl:element name="OriginPortId"><xsl:value-of select="XXX/*[local-name()='HouseBillsNode' and namespace-uri()=''][HouseBillNo = $ID]/*[local-name()='OriginPortId' and namespace-uri()='']" /></xsl:element>
<xsl:element name="ShippingAddress"><xsl:value-of select="YYY/*[local-name()='WayBillInfo' and namespace-uri()=''][WayBillNo = $ID]/*[local-name()='ShippingAddress' and namespace-uri()='']" /></xsl:element>
<xsl:element name="ContainerAddress"><xsl:value-of select="YYY/*[local-name()='WayBillInfo' and namespace-uri()=''][WayBillNo = $ID]/*[local-name()='ContainerAddress' and namespace-uri()='']" /></xsl:element>
</xsl:element>
</xsl:template>

Here XXX is the XPath from the root node down to the HouseBillsNode node and YYY is the XPath from the root node down to the WayBillInfo node.

Basically, the script is fired by the map for each HouseBillNo element that appears (3 in my example) and the script will create an Output element with the HousebillNo value and i will then use the number to look up the values that correspond to the key in the other parts of the input.

There are some drawbacks to this solution as well, and I will just try to summon up the drawbacks here:

Drawbacks for first maps

  1. If the elements do not appear in the exact same order in both inputs, the map will fail.

Drawbacks for the second map

  1. The script has not been adjusted to handle optional fields. So it will create the output fields no matter if the input fields exist in the source.

Drawbacks for both maps

  1. If the HouseBill input has more elements than the other, then the output will be missing values for the elements that would get there values form the second input.
  2. If the HouseBill input has fewer elements than the other, then the output will simply not have records corresponding to these extra elements in the WayBill input.
  3. Both scenarios can be handled in the XSLT, naturally, if needed.

There are probably other drawbacks – most of them related to the fact that I was too lazy to handle all exceptions that might occur. But you should get the idea anyway :-)

The solution can be found here

.

Hope this helps some one…

--
eliasen

Wednesday, March 25, 2009 11:26:40 PM (Romance Standard Time, UTC+01:00)  #    Comments [5]  | 
Tuesday, March 10, 2009

Hi all

I decided that it was time to put my functoid library which was earlier hosted at http://www.eliasen.eu/DownloadSoftware.aspx to Codeplex.

You can find them along with the documentation at http://eebiztalkfunctoids.codeplex.com/ from now on.

Cheers

--
eliasen

Tuesday, March 10, 2009 9:36:19 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  | 
Monday, March 9, 2009

Hi all

A couple of months ago, while trying to solve the If-Then-Else issue within a map in a nice way, a fellow BizTalk MVP suggested to me that I could just have the script inside a custom scripting functoid and then copy the script from custom scripting functoid to custom scripting functoid.

Naturally (as I assumed it was, back then) I told him that this was impossible, because BizTalk wouldn't let me have two custom scripting functoids which contains the same method, ie. the two methods have the same signature.

"Sure you can", he replied.... So I had to check it out... I fired up my BizTalk 2006 R2 virtual machine, and sure enough: He was right. I was in chock, because I was totally sure i was right. so I fired up a BizTalk 2006 virtual machine and again; He was right and I was wrong.

Now... those who know me will know that when I am convinced I am right, I will usually go to great lengths to prove it :-) So I stepped down a version and tried BizTalk 2004. Again no luck.

But FINALLY, when trying it on BizTalk 2002, it turned out that I was right. Back in BizTalk 2002, scripts were in VBScript and here you can not have multiple custom scripting functoids with methods with the same signature. In versions after BizTalk 2002, the compiler will collapse those methods into one, but in BizTalk 2000 and 2002, this is not done, and therefore an error occurs.

So all in all, I discovered this limitation back in 2003 and never questioned it again since. So let this be a lesson to all (especially me, because I always think I am right :-) ) - that sometimes we need to reevaluate what we think we know.

Hopefully this post will:

  1. encourage people to reevaluate opinions and knowledge
  2. inform others like me, who thinks that you cannot have the same method signature twice in a map, that this is wrong :-)

--
eliasen

Monday, March 9, 2009 9:51:43 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  | 
Sunday, March 8, 2009

Hi all

So, I have written two previous posts about how to solve the If-Then-Else problem in a map. The first post discussed the way to use built-in functoids to solve the issue. The second post discussed the issues I had creating a custom functoid to do the job.

Well, I now have a new way of doing it, which is not just one functoid, but still it's prettier than what I can do with the built-in functoids.

Basically, as discussed in my post about the issues with the different functoid categories, a functoid that is in the String category cannot accept a logical functoid as input. A scripting functoid can accept a logical functoid as input, but I can't create a custom scripting functoid where I decide what script to appear inside the scripting functoid at design time.

So the solution I am describing in this post is a combination of the two.

This screenshot describes a map that solves the If-Then-Else problem:

IfThenElse

The blue functoid with the crappy icon is programmed by myself. It is a simple functoid, which takes in three parameters, which are all strings. First, it tries to convert the first parameter to a boolean. If this fails, a "false" is assumed. Then, if the boolean was true, the second parameter is returned and if it was false, the third parameter is returned.

Now, since a string functoid cannot take a logical functoid as an input, I use a custom scripting functoid that is very simple:

public string Same(string str)
{
return str;
}

Which is really annoying to have to do, since... well... I take in a string and return the exact same string. Oh well...

You can find my functoid and the project that uses it as file downloads at the bottom of this post. Note, that the functoid library contains a whole bunch of functoids, of which only one is relevant. The library contains all the functoids I built trying to solve the If-Then-Else issue. The only needed functoid will be included in my downloadable functoid library at a later point.

Now, the advantages of this solution is, that it only requires three functoids all together. The best I could do with the built-in functoids were four, and five were sometimes the prettiest solution.

Functoid library: here

Project that uses the functoid: here

--
eliasen

Sunday, March 8, 2009 10:02:37 PM (Romance Standard Time, UTC+01:00)  #    Comments [2]  | 
Wednesday, February 4, 2009

Hi all

So, a colleague of mine is integrating with AS/400 and this system seems to be sending all strings as all-uppercase. So a company name might look like this: "JANS SUPERCOMPANY A/S". This really isn't what he wants output in the end, so I have built a functoid and added it to my downloadable collection, which converts the "JANS SUPERCOMPANY A/S" into "Jans Supercompany A/S". It has an optional set of strings that are not to be messed with :-)

Examples of output from the functoid. The second parameter is optional.

First input Second input Output
jan eliasen   Jan Eliasen
jan eliasen A/S JAn JAn Eliasen A/s
JAN ELIASEN A/S Jan,A/S Jan Eliasen A/S
This is a test string for the functoid tHIS,A,fOr,silly tHIS Is A Test String fOr the functoid

As always, you can download the functoid at http://www.eliasen.eu/DownloadSoftware.aspx - where you can also download the documentation.

--
eliasen

Wednesday, February 4, 2009 1:09:39 AM (Romance Standard Time, UTC+01:00)  #    Comments [0]  | 
Monday, January 5, 2009

Hi all

After I gave a BizTalk presentation at Aalborg .NET User Group I got a message from Søren Spelling Lund from Århus .NET User Group who wanted to interview me about BizTalk for a Podcast. Naturally, I accepted, and the result can be found here.

Only in Danish, I am afraid.

--
eliasen

Monday, January 5, 2009 8:26:20 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  | 
Tuesday, December 23, 2008

Hi all

I have added a new program to be downloaded for free from http://www.eliasen.eu/DownloadSoftware.aspx. This time it is a program to help you do two things:

  1. Check an XML file to see if it is well formed
  2. Validate an XML file against an XSD schema

I have had the need for a small utility to do this several times, in case a customer has some XML, and they want to know if the XML is even valid. The check for well formed-ness can be done by simply opening the file in Internet Explorer, but that is just soooo slow for large files. I tried a 70MB XML file once. It took IE a couple of hours to open it and tell me what was wrong with the XML. My utility did it in a few seconds.

So, use it if you want...

--
eliasen

Tuesday, December 23, 2008 9:38:25 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  | 

Hi all

Today, I took the 70-241 exam in BizTalk 2006 R2.

I passed, and am now MCTS: BizTalk Server 2006 R2 :-)

I have now passed the exams in BizTalk 2000, BizTalk 2004, BizTalk 2006 and BizTalk 2006 R2. Anyone else out there who has done this? :-)

--
eliasen

Tuesday, December 23, 2008 9:37:35 PM (Romance Standard Time, UTC+01:00)  #    Comments [3]  | 

Hi all

At Logica we often participate in different events where employees compete to see who rides their bike more often to work, who walks the most steps in a month, and so on. After a month of competition, we end up with a spreadsheet, where I may have walked 180.000 steps, but my colleague Henrik only walked 78.000 steps (He is kind of a wimp :-) )

So lets say that we want to give a prize to one of us, and Henrik should have a chance of 78000/(78000+180000) (30,23%) of winning and I should have a chance of 180000/(78000+180000) (69,77%) of winning. As the number of points and the number of contestants get bigger, this becomes increasingly difficult to manage.

Therefore, I have written a small winforms program, that helps you manage this. You can add as many contestants as you like, and give them points. If you are only interested in a "normal" draw, you can just give all contestants one point.

Screen shot:

eliasen.eu.draw.screenshot

The program not only does the draw, it will also:

  • Give you an overview of the contestants, their points and their chance of winning, which is dynamically updated each time a contestant is added
  • Give you the opportunity to simulate any number of draws, to ensure that the program is random. When doing the simulation, the percentage of wins by each contestant is shown next to the chance of winning, so they can be compared.

I will gladly take comments, bug reports, suggestions, postcards, et cetera :-)

The documentation can be found at http://www.eliasen.eu/DownloadSoftware.aspx#documentation and the program can be downloaded at http://www.eliasen.eu/DownloadSoftware.aspx#winform.

I hope this comes in handy to someone.

--
eliasen

Tuesday, December 23, 2008 9:27:44 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  | 

Hi all

I am using http://www.last.fm to keep track of what I listen to, and to get inspired to listen to some new music that I didn't know I liked.

You can find my profile at http://www.last.fm/user/eliasen and you can find information about an excellent Danish band Baal at http://www.last.fm/music/Baal. Please note, though, that I listen to the Danish band Baal, and not the Japanese band that unfortunately shares the band name Baal with the Danish band.

Anyway, the point of this blog post is, that it seems that I am currently the top listener of Baal:

baal_top_listener

:-)

This means that I listen to more Baal than all that listen to either the Danish or the Japanese band...

I know... Get a life, damn it! :-)

Baal have a web site at http://www.baalworld.com - try it! :-)

--
eliasen

Tuesday, December 23, 2008 9:27:19 PM (Romance Standard Time, UTC+01:00)  #    Comments [0]  | 

Theme design by Jelle Druyts