Solving the "If-Then-Else" problem in a map - part I

by eliasen 15. november 2008 20:49

Hi all

I have often wondered why the built-in functoids doesn't encompass an If-Then-Else functoid. The Value Mapping functoid only has an If-Then-part and not the Else-part.

This is the first of two blog posts. This post will explore how to solve the issue with the built-in functionality of BizTalk. The next post will be about creating a custom functoid to do the job instead and the issues that come with this task.

So, using the built-in functionality:

Imagine this input schema:

IfThenElseInputSchema

And imagine this output schema:

IfThenElseOutputSchema

My goal, now is to create a map that will map the value of the "ifJan" element to the destination IF the "qualifier" element equals the word "Jan" and otherwise the value of the "ifNotJan" element should be mapped.

So basically, given this input:

<ns0:IfThenElseInput xmlns:ns0="http://IfThenElse.IfThenElseInput">
  <qualifier>Jan</qualifier>
  <ifJan>ifJan</ifJan>
  <ifNotJan>ifNotJan</ifNotJan>
</ns0:IfThenElseInput>

I want this output:

<ns0:IfThenElseOutput xmlns:ns0="http://IfThenElse.IfThenElseOutput">
  <field>ifJan</field>
</ns0:IfThenElseOutput>

And given this input:

<ns0:IfThenElseInput xmlns:ns0="http://IfThenElse.IfThenElseInput">
  <qualifier>NotJan</qualifier>
  <ifJan>ifJan</ifJan>
  <ifNotJan>ifNotJan</ifNotJan>
</ns0:IfThenElseInput>

I want this output:

<ns0:IfThenElseOutput xmlns:ns0="http://IfThenElse.IfThenElseOutput">
  <field>ifNotJan</field>
</ns0:IfThenElseOutput>

Using a map and the built-in functoids, that would look like this:

 IfThenElseMap_Functoids

Basically, you need one value mapping functoid for each possible value to pass on, and a logical functoid for each value as well, to use in the value mapping functoid. The "String Concatenate" functoid is just my way of returning the string to use for the qualifier - in this case: "Jan".

You can also do it using one scripting functoid like this:

IfThenElseMap_Scripting_XSLT

where the scripting functoid is an "Inline XSLT Call Template" scripting type, and the script looks likes this:

<xsl:template name="IfThenElse">
  <xsl:param name="qualifier" />
  <xsl:param name="ifJan" />
  <xsl:param name="ifNotJan" />
  <xsl:element name="field">
    <xsl:choose>
      <xsl:when test="$qualifier='Jan'">
        <xsl:value-of select="$ifJan" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$ifNotJan" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:element>
</xsl:template>

Now... IF my good friend Henrik Badsberg is reading this, then by now he is screaming: "USE A BLOODY C# SCRIPTING FUNCTOID!!!!!" :-)

This, naturally is also an option:

IfThenElseMap_Scripting_CSharp

with an "Inline C#" script containing this script:

public string IfThenElse(string qualifier, string ifJan, string ifNotJan)
{
  if (qualifier == "Jan")
    return ifJan;
  else
    return ifNotJan;
}

Both scripting solutions can be altered to accept the output of a logical functoid as the first input. Just change the string "Jan" to "true" in the scripts, and change the name of the parameter if you want.

Now then... I am not a big fan of either of these three options. Generally, I avoid scripting functoids when I can because it is difficult for a new developer to know what is happening when he opens the map because he will have to open up all scripting functoids and find out (and remember) what they do. Also, I am not really a big fan of the first solution either. First of all, there are too many functoids, and it can messy if this solution is needed several times in a map. Secondly, you get a warning every time you compile, because you have two inputs to one element.

You can find my project with the three working maps here.

In my next post, I will look into creating a custom functoid that does the job and I can tell you right now; That isn't as easy as I had imagined...

--
eliasen

Tags:

BizTalk 2004 | BizTalk 2006

Transactions giving you a headache

by eliasen 10. november 2008 18:28

Hi all

In almost all multiple server installations of BizTalk I have encountered, there has been issues with MSDTC. MSDTC is Microsofts product for handling distributed transactions, meaning transactions that span multiple servers. BizTalk uses this in high scale, when running transactions against SQL Server, to maintain consistency in BizTalks databases.

All issues with MSDTC are solvable - sometimes it is just hard to figure out what is wrong.

First of all, always use the DTCTester tool at http://support.microsoft.com/kb/293799 to test your MSDTC installation. If this tool reports no errors and you are still having issues, then most likely, MSDTC isn't the cause of your issues.

If something is wrong with MSDTC, I have encountered four major issues:

  1. MSDTC doesn't run on either of the server. Solve this by starting MSDTC. Steps to start MSDTC (Note, that the MMC snapin is buggy, and it might appear that the "Component Services" node has no children... but it does, trust me :-) ):
    1. Go to "Administrative Tools" => "Component Services"
    2. Go to "Component Services" => "Computers" => "My Computer"
    3. Right click "My Computer" and choose "Start MS DTC".
      start_msdtc
  2. MSDTC isn't configured for network access on both servers. Solve this in "add/remove windows components" here:
    install_msdtc_network_access
  3. The two servers have the same MS DTC ID. This ocurs if both servers are clones of the same server or if one of the ervers is a clone of the other server. Usually, when cloning servers, sysprep is used to clear out those errors, but in case it hasn't been used, here is how you fix it:
    1. Run "msdtc -uninstall" from a command prompt
    2. reboot
    3. Run "msdtc -install" from a command prompt
    4. reboot
  4. You can't ping the servers by hostname, which is required. This basically means, that from both servers, you need to be able to ping the other server by hostname - pinging by IP address isn't enough. If you can't ping by hostname, you have two options:
    1. Get the network administrator to update your DNS
    2. Enter new information into the hosts file in c:\windows\system32\drivers\etc

Hope this helps.

--
eliasen

Tags:

BizTalk 2004 | BizTalk 2006

System.Exception vs. General Exception

by eliasen 12. december 2007 18:53

So...

People sometimes ask, what is the difference between catching System.Exception and the General Exception in a Catch Exception shape in the orchestration designer in BizTalk.

Off course, an obvious difference is, that with the General Exception, you don't get an object with properties to investigate. But then it seems that the General Exception is useless... surely there is a point to it?

Well, I was curious about this myself, so I investigated a bit, and found this post. So basically, I think the catch of the general exception in BizTalk 2006 is a left over from BizTalk 2004. In BizTalk 2004 it made sense, since you actually have exceptions thrown at you that didn't derive from System.Exception. That is no longer possible in .NET 2.0 - they just haven't removed it from the designer - probably just to be backwards compatible.

That's it...

--
eliasen

Tags:

BizTalk 2004 | BizTalk 2006

XML disappearing when calling a BizTalk Web Service

by eliasen 21. november 2007 23:34

Hi

Recently, I ran into a peculiar problem, which really had me fooled a long time.

Basically, I had a BizTalk Server 2006 R2 solution running. It consisted of 10 assemblies. One of the orchestrations in each of 9 of the assemblies was exposed as a web service, all using complex types - no strings, ints and so on.

And then there was the system, that was to call my web services. I had no saying over that system. We started calling the first web service. Everything went ok. Then they implemented code to call the second web service, everything OK... all was well (except some minor things here and there) for the first eight web services.

But at the ninth web service, strange things started to happen.

Basically, the other system would call my web service, IIS would return http 200 OK, but still, no data came into BizTalk. I had NOTHING in group hub page, nothing in HAT, nothing in the eventlog, NOTHING! IIS log said: I received a post on this url and responded with 200 OK - that's it - nothing more.

Really weird - I mean... where did the XML go? Why were there no errors? So we installed YATT, which is an http sniffer tool, that would be able to tell us what was exatly sent across the wires. Basically, what we found out was, that allthough the sender might have send 13000 bytes, the sniffer only reported maybe 10500 bytes. So we started investigating the network. The two servers were on the same subnet, one hop away from eachother. So no servers on the route could mingle with the traffic.

I decided that I would write my own little C# test program, that would call the web service and see if that failed as well. It didn't. I ended up calling the web service succesfully with more than 100k (I didn't bother to try anything higher than that.)

But it turned out, that the sniffer must have a bug - it reported all sorts of different numbers, when using my test program, and none were correct. Apparently, it wasn't created to handle large packets, but just a few kilobytes. So we installed wireshark instead (get it from sourceforge). Now THAT is a nice tool! Totally professional (and free), and it showed us everything that came in and out - no limitations.

So we did a test with my tool, and a test with the other system, and tried comparing the http headers, the soap action, and so on. It turned out, that all the other web services, when called by the other system, returned http 202 Accept and not http 200 OK. And when my test program called the web service, it got the http 202 Accept.

We ended up discovering what the issue was. The other system (programmed in .NET) wasn't calling my web services the "right way". They were sending everything using httprequests. Now, this is a perfectly legal way of doing it, but it really requires that you know what you are doing. I mean: They added a header to the httprequest for the SOAPAction, and then they built up XML with the soap envelope, soap body, elements for the web method and inside that the actual XML. This was just a string that they sent using httprequest.

The answer ended up being that the XML that the other system was sending me had invalid data in elements of type xsd:date. So basically, the XML couldn't be deserialized into the object that my web method on the web service was expecting. Therefore, the web method was never called, and therefore there was no data in biztalks log, the eventlog or anywhere else.

So, I have learned two things from this:

1. You should always accept the help your programming environment gives you. If the programmer of the other system had added a web reference to the web service and built XML and deserialized it into the object that was the parameter, he would have gotten an exception at runtime, that he could debug. The way he did it meant that we got NO errors at all - the data just disappeared (which I think .NET shouldn't do. Some sort of warning somewhere would have been nice.)

2. When debugging, don't trust the tools you download you to help debugging :-)

I hope this can help someone.

--
eliasen

Tags:

.NET | BizTalk 2006

Error configuring BizTalk Server 2006 R2

by eliasen 21. oktober 2007 18:02

Hi

I just thought I would share my experiences from the first BizTalk 2006 R2 I have installed and configured.

It was on two different boxes - one for SQL Server and one for BizTalk. Domain groups were created beforehand, as well as a service account for the services. So everything should be in place.

Installation went fine, naturally, but the configuration wouldn't let me configure Group and Runtime. I checked the logs, off course, and the first error was this one:

[09:14:15 Info ConfigHelper]  is not a local entity.
[09:14:15 Error ConfigHelper] d:\depot2300\mercury\private\common\configwizard\confighelper\service.cpp(729): FAILED hr = 80070421

[09:14:15 Warning ConfigHelper] The account name is invalid or does not exist, or the password is invalid for the account name specified.
[09:14:15 Warning ConfigHelper]  Failed to validate service credentials for account: %1

So it had to be something about the credentials I have specified. So I unconfigured, reconfigured, being very carefully to enter the correct credentials - same error. I tried again, with extra extra focus on not mistyping anything. Same error.

Then I searched some more in the log file, and found this:

2007-09-25 09:16:49:0441 [INFO] WMI Deploying 'C:\Program Files\Microsoft BizTalk Server 2006\Microsoft.BizTalk.GlobalPropertySchemas.dll'
2007-09-25 09:16:49:0723 [WARN] AdminLib GetBTSMessage: hrErr=80070002; Msg=The system cannot find the file specified.;
2007-09-25 09:16:49:0723 [WARN] AdminLib GetBTSMessage: hrErr=c0c02560; Msg=Failed to read "KeepDbDebugKey" from the registry.
The system cannot find the file specified.;

But the file actually existed. Then I searched the log file some more, and found this:

2007-09-25 09:16:49:0863 [INFO] WMI Error occurred during database creation; attempt to rollback and delete the partially created database'hcpr-hd-axa-01\BizTalkMgmtDb'
2007-09-25 09:16:49:0863 [INFO] WMI Calling CDataSource.Open() against hcpr-hd-axa-01\master
2007-09-25 09:16:49:0879 [INFO] WMI CDataSource.Open() returned
2007-09-25 09:17:09:0942 [WARN] WMI Rollback failed.  Could not delete database.
2007-09-25 09:17:09:0942 [ERR] WMI Failed in pAdmInst->Create() in CWMIInstProv::PutInstance(). HR=c0c025b3
2007-09-25 09:17:09:0942 [ERR] WMI WMI error description is generated: Exception of type 'System.EnterpriseServices.TransactionProxyException' was thrown.
2007-09-25 09:17:09:0942 [INFO] WMI CWMIInstProv::PutInstance() finished. HR=c0c025b3
[09:17:09 Error BtsCfg] d:\depot2300\mercury\private\mozart\source\setup\btscfg\btswmi.cpp(358): FAILED hr = c0c025b3

[09:17:09 Error BtsCfg] Exception of type 'System.EnterpriseServices.TransactionProxyException' was thrown.
[09:17:09 Error BtsCfg] d:\depot2300\mercury\private\mozart\source\setup\btscfg\btscfg.cpp(1769): FAILED hr = c0c025b3

This error pointed to some transaction error, so I downloaded and ran dtctester and it turned out my MSDTC settigns were not good enough. I spend the better part of a day looking for this. What really had me confused was that the SSODB was created fine - the BRE-DB was created fine... and the BizTalkMgmtDb database was sometimes created just fine. I mean... sometimes it would create the BizTalkMgmtDB database and fail during creation of the MessageBox. Other times it would fail on the Management database. So seing as two databases were created just fine, I really didn't think there were any issues with DTC.

BUT, this just goes to show; Before starting a multibox installation of BizTalk, ALWAYS run dtc tester first - just to be sure :-)

--
eliasen

Tags:

BizTalk 2006

The specified path, file name, or both are too long.

by eliasen 14. oktober 2007 19:52

Hi

The other day I published an orchestration of mine as a web service. Not a big deal. Then, I needed to export the MSI for my application, so I could install it on the test server. Now THAT was a Big Deal! :-)

I got this one:

A really silly restriction on a quite normal Windows Server 2003 R2 - as you can see, the entire path of a file, including the filename, must be less than 260 characters long. And the path itself must be less than 248 characters long.

This had me stunned for a moment, until I took a closer look at what file creation was the issue. It turns out, that the issue was with creating temporary files in c:\documents and settings\administrator\local settings\temp. Yes, I am logged in as administrator. No, I wouldn't normally do that. Quit asking these questions, and let me finish the post! Right. Then I got clever, if I might say so myself (nobosy else is saying it, so I suppose I have to do it myself :-) )... Turns out that the temporary files are created in the %TMP% (NOT the %TEMP% one...) directory. So what to do? Simple - change the %TMP% environment variable to point at c:\tmp in stead of c:\documents and settings\administrator\local settings\temp. That's what I did, and it worked. I got my MSI file.

BUT... Well... You know that sometimes you do something that is like peeing in your pants? At first it is warm, but then it just gets cold and nasty? Well, this is like that. Because when I then took the MSI file to the test server and tried to install it (not the import part, but the install part), I got the exact same error. The default installation path is C:\Program Files\Generated by BizTalk\ - which is also a rather long path. So in order to install my application, I ended up installing it to c:\biz. Now having to tell your customer that they can't install the application to a path longer than 5 characters really isn't an option.

So my clever and very nice workaround to just set the TMP environment variable to c:\tmp in order to generated the MSI file really wasn't all that clever, since the installation wasn't acceptable at all. Had the issue just been my own developers box, I wouldn't have minded... but now I have to go rename all artefacts anyway. Bugger!

So basically, this post is written for people looking for a workaround for the error they get with long filenames/paths. My suggestion: Rename your artefacts, and don't wet your pants! :-)

--
eliasen

Tags:

BizTalk 2006

BizTalk vNext wishlist

by eliasen 6. oktober 2007 22:40

Hi

Well, some people have their BizTalk vNext wishlist on their blog. I'd like to add a couple of requests to the growing list :-)

  1. For development purposes, it would be really nice to be able to rightclick a receive location that is disabled and choose "Execute". If for instance I have a SQL adapter receive location that is supposed to poll every minute, then I don't want to have to quickly disable the receive location once it has been fired. I want to keep it disabled, so data wont go through my system when I am not ready, and then just execute it whenever I am ready.
  2. Deployment of single assembly from VS.NET. If I have three projects in my solution: Schemas, Maps and Orchestrations, and both Maps and Orchestrations reference Schemas, then I can not deploy them all at the same time from VS.NET :-( Deploying Orchestrations will make VS.nET deploy Schemas as well - even if there are no changes to it. To deploy Schemas, the current Schemas assemblymust be undeplyed, and therefore, the Maps assembly must also be undeployed. So VS.NET will Undeploy Orchestrations, Undeploy Maps, Undeploy Schemas, Deploy Schemas, Deploy Orchestrations. This isn't acceptable, because Maps isn't deployed anymore. If I then deploy Maps, the same thing happens, only the Orchestrations gets undeployed and it isn't redeployed. To me, VS.NET should ONLY interfere like that if I deploy the entire solution. If I deploy just project, then just let me do so! Right now, I would have to let Orchestrations reference Maps even if it isn't necessary and then always deploy Orchestrations.
  3. Restart Host Instances only once. Right now, if I deploye my solution from VS.NET, and this solution has 10 proejcts that are all set to "Restart Host Instances" on deployment, then the host instances will get restarted 10 times. Would be nice if VS.NET could figure this out and only do it once.
  4. Specify the node that is body, when using enveloping and not just the parent. It makes great sense, that I can specify a node and all child elements are then submitted as seperate messages from the receive pipeline. This is how we can receive orders, invoices, etc. in the same XML. BUT, if I receive XML where I only need the Orders, then I would like to point at the Orders element so that is all I get. Right now I have to use standard enveloping, and implement logic to just delete the invoices, etc. Not really nice, I think.

That's it for now :-)

--
eliasen

Tags:

BizTalk 2006

Creating a specific number of elements in destination of map.

by eliasen 6. oktober 2007 22:09

Hi

A guy on the newsgroups recently needed to create exactly 5 elements in the output of his map, no matter how many records appeared in the input.

Well, I am always looking for new things to try out, and frankly, my XSLT coding skills could be better, so I thought I'd give it a shot.

I created a project with the following input schema:

The schema is for an XML document, and has a header (1..1), a LoopingRecord (1..1) and a footer (1..1). The LoopingRecord has a Field5 element, that can appear at most 5 times.

The output schema looks like this:

This schema is for a flat file. It baiscally has the same signature as the input schema - exception being that the Field1 element has minOccurs=5. It MUST be present 5 times - this is a schema for a positional file.

The map is pretty simple:

Header and footer are mapped using regular mapping techniques. But the Detail-element is created using a custom scripting functoid.

The string concatenate functoid only has one input, the string "5". This is because I want to create exactly 5 elements in the ouput.

The custom scripting functoid is an "Inline XSLT Call TEmplate" scripting functoid with the following code:

<xsl:template name="CreateXElements">
   <xsl:param name="totalCount" />
      <Detail>
         <xsl:for-each select="/*[local-name()='InputRoot']/*[local-name()='LoopingRecord']/*[local-name()='Field5']">
            <DetailLoop>
               <Field1><xsl:value-of select="text()" /></Field1>
            </DetailLoop>
         </xsl:for-each>
         <xsl:variable name="countRecords" select="count(/*[local-name()='InputRoot']/*[local-name()='LoopingRecord']/*[local-name()='Field5'])" />
         <xsl:if test="$countRecords&lt;$totalCount + 1">
            <xsl:call-template name="BuildTheRest">
               <xsl:with-param name="counter"><xsl:value-of select="$countRecords + 1" /></xsl:with-param>
               <xsl:with-param name="totalCount"><xsl:value-of select="$totalCount" /></xsl:with-param>
            </xsl:call-template>
         </xsl:if>
      </Detail>
</xsl:template>
<xsl:template name="BuildTheRest">
   <xsl:param name="counter" />
   <xsl:param name="totalCount" />
      <DetailLoop>
         <Field1></Field1>
      </DetailLoop>
      <xsl:if test="$counter&lt;$totalCount">
         <xsl:call-template name="BuildTheRest">
            <xsl:with-param name="newCounter"><xsl:value-of select="$counter + 1" /></xsl:with-param>
         </xsl:call-template>
      </xsl:if>
</xsl:template>

Basically, I start by copying existing nodes to the destination. As I have explained in this post you need to use XSLT for the whole thing. You can't copy the existing nodes using the mapper and create the new nodes using XSLT. After the existing nodes have been copied, I create the new empty nodes, by recursively calling a template that will create a single element for me.

You can find my entire project here: CreateXNumberOfElements.zip (23.33 KB)

I hope this will come in handy for someone in the future.

--
eliasen

Tags:

BizTalk 2006

Overwriting adapter properties

by eliasen 18. september 2007 20:29

Hi

An old collegue of mine asked me if there wasn't anyhow he could overwrite the folder of a send port using the FILE adapter, so that he could decide the entire path of a file that was to be written from within his orchestration.

After all, you can overwrite many things, like SMTP server to be used in the send port or the username and password for an FTP connection. So why not the file folder?

Well, I have investigated it a little bit, and I can't get around to making BizTalk do it.

I tried:

  1. Set the folder on the send port blank, and use the %SourceFileName% as filename and set its value (The FILE.ReceivedFileName property of the message) inside the orchestration. This isn't valid, since the folder path can not be empty.
  2. Set the folder to c:\ and set the FILE.ReceivedFileName property to be <directory> + "\\" + <filename>. This didn't work either. When writing the file, BizTalk strips all folder names from the FILE.ReceivedFileName value and just wrote the file with filename in c:\

Off course, you can use a dynamic port to do it, but this customer wanted to avoid seeing all those subscriptions in the subscription viewer.

So I don't see a way around it. And basically, when you know it works like this, it makes sense that the administrator who has decided what folder files go into also gets to decide that you can not overwrite this. Oh well, that's life.

Hope this helps someone at some point...

--
eliasen

Tags:

BizTalk 2006

Promoting reoccuring elements

by eliasen 16. september 2007 21:22

Well, I suppose we have all been there – in order to get the business process running, a specific element from a schema needs to be promoted in order to route on it, correlate on it, and so on.

 

Unfortunately, elements that can occur more than once can not be promoted. This, off course, makes perfectly sense, since the property can only hold one value, and how would BizTalk know which one of the many occurring elements to take the value from at runtime? So we agree with the limitation, but hope for a nice solution. :-)

 

If you try to promote a reoccurring element, you get this error when adding it to the list of promoted properties:

“This node can occur potentially multiple times in the instance document. Only nodes which are guaranteed to be unique can be promoted.”

 

Right. Now, some people have found the editor for the XPath describing the element that one wants to promote. If you have promoted some element, you can click on it like this:

Then you can click on the dot at the right of the line, and get into the editor like this:

 

Now, wouldn’t it be lovely, if you could just change this expression to include for instance an index on the reoccurring element? In my example from this screenshot, the “ReoccuringRecord” record can occur multiple times. So it would be nice, if I could just change the XPath to be like this:

 

/*[local-name()='ExampleRoot' and namespace-uri()='http://PromotingReoccuringElement.ExampleSchema']/*[local-name()='ReoccuringRecord' and namespace-uri()=''][1]/*[local-name()=’ElementWhereNumber1IsPromoted’ and namespace-uri()='']

 

By setting the “[1]” into the XPath, I state that I will be needing the first occurrence of the ReoccuringRecord and therefore, this XPath expression will always give me exactly one node. Unfortunately, the engine can not see this, so the error will be the same, only difference being that this error doesn’t occur until compile time:

 

Node "ElementWhereNumber1IsPromoted" - The promoted property field or one of its parents has Max Occurs greater than 1. Only nodes that are guaranteed to be unique can be promoted as property fields.

 

Bummer!

 

So how do we get this working? If I really need to promote a value that occurs in an element that might occur multiple times, I see four options:

 

  1. Map to a schema on receive port
  2. Custom pipeline component
  3. Orchestration to do it and then publish to MessageBox
  4. Call pipeline from orchestration

I will go these options in more detail here:

 

Option 1: Map to a schema on receive port.

When a map is executed on a receive port, some extra magic functionality is performed by BizTalk. After the map has been executed, the message is sent through some code that promotes properties that are specified inside the destination schema. If you execute a map inside an orchestration, this doesn’t happen.

 

So you can create a schema that has an extra field, in which you place the value that needs to be promoted. This element must not be able to occur multiple times. Promote this new field, and after the map on the receive port has been executed, you have your value promoted.

 

Option 2: Custom Pipeline Component.

It isn’t that difficult to create a custom pipeline component, that can promote a field for you. Your Execute method might look just like this:

 

public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)

{

    pInMsg.Context.Promote("MyProp", "http://ReoccuringElement.PropertySchema", "MyValue");

    return pInMsg;

 }

 

Of course, you will probably want to load the body stream of the IBaseMessage somehow, in order to find the value inside the body to promote and then replace "MyValue" with the value form within the XML.

 

Just use the pipeline component inside a custom receive pipeline, and you are all set.

 

Option 3: Orchestration to do it and then publish to MessageBox

Create a intermediate orchestration, that gets the input message. Then, it should create a new message of the same type in a message assignment shape like this:

NewMessage = InputMessage;

NewMessage(*) = InputMessage(*);

NewMessage(MyNewProperty) = xpath(InputMessage, xpathexpression);

 

Then, use a direct bound port to publish the message to the MessageBox. In order for the new property to follow the message, you need to initialize a correlation set on the send shape that is based on this new property.

 

Let other orchestrations and send ports subscribe to this message and let then do their work.

 

Option 4: Call pipeline from orchestration

The last option is to call a receive pipeline from within your orchestration. This requires a new schema, that has a field for the value to be promoted, just as in option 1. Inside your orchestration, map the input message to this new schema, and call a receive pipeline with this new message as a parameter. Remember to promote the field in this new schema. There is an article on MSDN about calling a pipeline from within an orchestration, which can be found at http://msdn2.microsoft.com/en-us/library/aa562035.aspx

 

Upsides and downsides

In order to choose which way to go in a specific solution, several things need to be considered.

 

Basically, I'd go for option 1 almost anytime. This is because it is best practices to map anything incoming into a canonical schema anyway. So instead of promoting values inside all your partners schemas - schemas they might change, you should promote from within your own canonical schema.

 

Reasons not to choose option 1 include: The canonical schema also has a reoccurring element, so it hasn't provided extra functionality with regards to getting this specific value promoted. Or perhaps, we aren't using canonical schemas, because there was no time for this when the project was started.

 

If we can't go for number 1, I'd go for number 3. Number 2 requires programming of a pipeline component, which can be a bottleneck, unless done correct. Also, the pipeline component is a whole new component to maintain, document and test. Number 4 requires a new schema and therefore also a map to be built. If I am ready to do this, I'd go for number 1 instead.

 

If I don't like number 3, for unknown reasons, I'd go for option 2 - the custom pipeline component. Allthough it is custom code, and must be done right, and testet and everything... I still feel that creating a new schema and map in order to call the pipeline in option 4 is overkill, since I'd go for option number 1 instead, which would also require the new schema and map.

I hope this explains some details about this issue, and that it helps someone in the future.

--
eliasen

Tags:

BizTalk 2006

About the author

Jan Eliasen is 37 years old, divorced and has 2 sons, Andreas (July 2004) and Emil (July 2006).

Jan has a masters degree in computer science and is currently employed at Logica Denmark as an IT architect.

Jan is a 6 times Microsoft MVP in BizTalk Server (not currently an MVP) and proud co-author of the BizTalk 2010 Unleashed book.

BizTalk Server 2010 Unleashed


Buy from Amazon

Microsoft MVP


6 times: July 2004, July 2008, July 2009, July 2010, July 2011, and July 2012. Not currently an MVP.

MCTS

Image to show

Month List

Page List