Sunday, 05 November 2006

Hi

A guy on the microsoft.public.biztalk.orchestration newsgroup has asked about looping around elements inside an orchestration, and I thought I'd just write some lines about the issue here, for everybody to see in the future.

The problem is, that he has the following document structure:

<Employees>
<Employee title="mgr">
</Employee>
<Employee title="vp">
</Employee>
<Employee title="ceo">
</Employee>
</Employees>

And he wants to do something with each employee, based on what the title is. As I see it, there are two options:

  1. Loop through the Employee-elements inside the orchestration
  2. Use an envelope to split the incoming Employees-message into several Employee-messages

Suggestion 1

I have proposed the following two schemas:

 for the big message that arrives and  for the individual Employee. Note, that I have promoted "title" as a distinguished field.

I then create an orchestration, that takes an instance of the Employees schema as input, and loop around the employees. The orchestration looks like this:

It receives the incoming message, and then initializes a couple of variables. The first expression shape, named "Initialize Loop variables" contains the following three lines:

empCount = xpath(InputMessage, "count(/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()=''])");
counter = 1;
counterStr = "1";

Basically, I get the number of employee-elements, and initialize the counter. The stringcounter is used to build xpath expression later, as you will see.

Then, I loop. The loop condition is "counter <= empCount" - so I want to loop as long as there are employees.

Inside the scope, I have declared a message employeeMessage, which is of the type of a single employee.

In the message assignment shape, I do this:

EmployeeMessage = xpath(InputMessage, "/*[local-name()='Employees' and namespace-uri()='']/*[local-name()='Employee' and namespace-uri()=''][" + counterStr + "]");

It takes the employee from the big incoming message that corresponds to the counter and assigns it to the message that is to be constructed.

In the next expression shape, I just write the content of the distinguished field "title" of the employee to the eventlog.

And in the final expression shape, I increment the counter variables:

counter = counter + 1;
counterStr = System.Convert.ToString(counter);

So by doing this, I am looping over the employees inside the employees-message, and I have access to all the values inside the single employee. I didn't have to have schema number 2, describing a single employee, I could have just used xpath all the way down, or maybe declare an XmlNode variable to hold the employee-element instead. But I like this solution better.

Another option I have now is that I can add a decision shape, and based on the title value, I can call different orchestrations, that will handle a specific employee-type. Or perhaps I could just send the employee message to a direct-bound send port and have other orchestrations subscribe to the employee message type. This would require the title to be a promoted property instead of a distinguished field, though, in order to route on it.

Suggestion 2

I propose using an XML Envelope to split the incoming file into several employee-messages and let the orchestration handle them individually.

To do this, I have created two schemas:

 for the envelope and  for the employee. Note: I have changed the names of the root nodes in both schemas. Naturally, in real life you wouldn't do this. The only reason I did this is to be able to have both my examples deployed at the same time. If I hadn't done it, I would have had multiple schemas deployed with the same combination of target namespace and root node, which we all know is BAD. On the schema for the envelope, I have clicked on the "<Schema>"-node and in the properties windows, I have set "Envelope" to "Yes". Then, I clicked on the "EmployeesEnvelope"-node and in the properties window, I set the "Body XPath" property to point at the "EmployeesEnvelope"-element.

Then, I created an orchestration, that takes an employee as the input - not the employees-type, but the single employee. It looks like this:

So here I have a much smaller, simpler, and faster orchestration than the one from suggestion 1.

After the solution is deployed, I create a receive location, and remember to use the default XMLReceive pipeline. The disassembler stage will look at the incoming message, determine the message type, see it is an envelope, split the message into smaller messages, and publish them individually with their own message type.

If I need different orchestrations depending on the value of the title attribute, I can promote it to a promoted property instead of a distinguished field, and add it to a filter on the receive shape in each orchestration.

Examples:

I have my two samples here: LoopAroundEmployee.zip (68,66 KB) and here: LoopAroundEmployeeEnvelope.zip (48,64 KB)

I hope this has been useful for someone. If you have any questions, just ask.

--

eliasen

Sunday, 05 November 2006 14:04:11 (Romance Standard Time, UTC+01:00)  #    Comments [13]  | 
Monday, 23 October 2006
Hi!

Recently a couple of different question askers at the microsoft.public.biztalk.something newsgroups have been asking questions about how to expose a BizTalk orchestration that takes an System.Xml.XmlDocument as input and also returnes a System.Xml.XmlDocument.

Basically, it is straight forward:
  1. You define two messages in your orchestration as being of the type "System.Xml.XmlDocument"
  2. You add a receive shape that accepts one of the messages
  3. You add a construct shape that constructs the return message
  4. You add a send shape that sends the output message
  5. You add a public request-response port and connect the receive- and send shapes to this port.
  6. You publish the orchestration using the Web Services Publishing Wizard.
A couple of issues:
  1. If you are deploying the web service to the same web site as your Windows SharePoint Services is running on, you have to exclude the path to the new web service, so that WSS wont try to take over the calls to the web service. This is done like this:
    • Administrative Tools
    • SharePoint Central Administration
    • Configure Virtual Server Settings
    • Choose the web site you have extended with WSS and to which you now want to deploy a web service
    • Define Managed Paths
    • Under "Add new Path", add your path and click "excluded path" and "OK"
  2. The virtual directory that is created by the wizard must run under an application pool that is running under a user that is a member of the "BizTalk Isolated Host Users". Otherwise you will get a SOAP exception when trying to call the web service.
And another thing that someone had dificulty with: When writing a small application to test the published web service, he got an error that said:
Compilation error:

            Error    1    The best overloaded method match for
'UNTTest.ws.UntypedWebService_Orchestration_That_Receives_and_Sends_XML_InputOutputPort.SendXMLAndGetAnswer(ref
System.Xml.XmlNode)' has some invalid arguments    C:\Documents and
Settings\simon.brooks\My Documents\UNTTest\Form1.cs    25    13    UNTTest

            Error    2    Argument '1': cannot convert from 'ref
System.Xml.XmlDocument' to 'ref System.Xml.XmlNode'    C:\Documents and
Settings\simon.brooks\My Documents\UNTTest\Form1.cs    25    41    UNTTest

Basically, the web service doesn't take an XmlDocument as a parameter, as one would have expected, but an XmlNode instead.

So after creating an XmlDocument to send to the web service, define an XmlNode object, and set it to point to the DocumentElement property of the XmlDcoument, and send that instead.
Like this:
            XmlDocument xmldoc = new XmlDocument();
            xmldoc.LoadXml("<rootnode><element1>value1</element1></rootnode>");
            XmlNode node = xmldoc.DocumentElement;
            WebserviceReference ws = new WebserviceReference();
            ws.Operation_1(ref node);

I hope this helps.

My sampel BizTalk project can be found here: UntypedWebService.zip (102.58 KB)

Should you have any comments, feel free to post them.

--
eliasen
Monday, 23 October 2006 00:01:48 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 
Friday, 13 October 2006

Hi

Every now and then, I come across the need of adding a node to the output of a BizTalk map.

Now, if I just want to add some node which isn't dependent on the input, I can just use a custom scripting functoid which is an XSLT template that just craeted the node for me, like this:

Use the "Inline XSLT Call Template" instead, if you need parameters to your XSLT.

BUT, sometimes I need to add a node to a list of existing nodes. One example of this I came across was the need to have a log inside the XML structure that was updated every time BizTalk touched the document. So there would be a structure inside the XML like this:

<TheLog>
<LogEntry>This is the first log entry and it was added by Jan</LogEntry>
<LogEntry>This is the second entry and it was added by BizTalk</LogEntry>
</TheLog>

So BizTalk needed to add a line to TheLog when BizTalk mapped the document.

Another example is a guy on the microsoft.public.biztalk.general newsgroup that needs to add an OrderItem to an existing list of OrderItems.

To do this, I have only found one solution, which is a custom xslt script that does the whole thing.

My example input schema:

My example output schema:

In both schemas, the "Order"-element can occur multiple times.

The map looks like this:

Basically, just one scripting functoid. Note that no links go from the source document. The scripting functoid is a "Inline XSLT" type, and the source is this:

<xsl:for-each select="//Orders/Order">
<xsl:element name="Order">
<xsl:element name="Ordernumber"><xsl:value-of select="Ordernumber" /></xsl:element>
<xsl:element name="OrderAmount"><xsl:value-of select="Amount" /></xsl:element>
</xsl:element>
</xsl:for-each>

<xsl:element name="Order">
    <xsl:element name="Ordernumber">400</xsl:element>
    <xsl:element name="OrderAmount">40</xsl:element>
</xsl:element>

Basically, the for-each creates line in the output according to the input XML document. And the xsl:element after the for-each creates the new node.

You can find my BizTalk 2006 project here: AddingANode.zip (16,89 KB) - it should work with BizTalk 2004 as well.

I hope this has helped someone. Comments are welcome.

--

eliasen

Friday, 13 October 2006 23:26:57 (Romance Daylight Time, UTC+02:00)  #    Comments [3]  | 

Hi

A user in the microsoft.public.biztalk.general newsgroup has a challenge he'd like solved.

Basically, he has this structure:

<Root>
  <Employee>
     <EmployeeID>1</EmployeeID>
     <JobsAssigned>10</JobsAssigned>
  </Employee>
  <Employee>
     <EmployeeID>2</EmployeeID>
     <JobsAssigned>5</JobsAssigned>
  </Employee>
  <Employee>
     <EmployeeID>3</EmployeeID>
     <JobsAssigned>8</JobsAssigned>
  </Employee>
</Root>

And he needs to find the EmployeeID of the employee that has the least jobs assigned to him/her. In this case, he needs the value "2".

This is a case, where the "Cumulative Minimum" functoid can be used.

So, I have this input schema:

and I have this fictitious output schema:

To do the task, I use this map:

Basically, I just map the fields, and then I make sure the "MinValues"-record is only created when the JobsAssigned value is equal to the cumulative minimum of the JobsAssigned.

The "Cumulative Minimum" functoid will return the smallest number of all the numbers it is given as input.

So, given the above mentioned input instance, the output of this map will be:

<ns0:OutputRoot xmlns:ns0="http://CumulativeMinimum.OutputSchema">
<MinValues>
  <Employee>2</Employee>
  <JobsAssigned>5</JobsAssigned> 
</MinValues>
</ns0:OutputRoot>

which, luckily, was what we needed :-)

Given an instance with more than one Employee hacing the same number of JobsAssigned and if this number is the minimum, the map will actually create a node for each.

As I don't know more of what the question-asker wants, I will let this be enough for now. Should it not be ok to return more than one EmployeeID in the output, the map will need to be changed.

I hope this has helped someone.

You can find a BizTalk 2006 project here: CumulativeMinimum.zip (4,51 KB)

The same will work for BizTalk 2004 - I just haven't been bothered creating the example. Let me know if you need it.

--

eliasen

Friday, 13 October 2006 22:23:30 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 
Thursday, 12 October 2006

Hi

It so really annoys me whenever I have to change my ways of doing things because some people insist that it is okay to bother others.

Spam is a great example - the mere fact that I can't write my email address in a public place without receiving spam the next day. Sigh.

Anyway, I, as many others, have disabled trackbacks on my blog, since it was filling up with porno and other stuff.

Should anyone have a good solution for dasBlog, le tme know :-)

--

eliasen

Thursday, 12 October 2006 15:37:36 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 
Wednesday, 27 September 2006
Hi

In my RSS aggregator I have the sourceforge file releases for dasBlog as a feed.

So the other day I read that a new version of dasBlog had been released.

Well, today I have finally had the opportunity to upgrade to the new version.

Should you notice anything weird, please let me know.

--
eliasen

Wednesday, 27 September 2006 22:32:21 (Romance Daylight Time, UTC+02:00)  #    Comments [0]  | 

Hi

I received the diploma for passing the 74-135 exam in BizTalk server 2004 the other day.

And... well... see if you can spot the error:

I have phoned support. They will correct it and send me another diploma. Until then, I am very proud to be the only person in the world (unless anyone else has gotten the same diploma?) that is certified in BizTalk Server 2003 :D

--

eliasen

Wednesday, 27 September 2006 20:49:33 (Romance Daylight Time, UTC+02:00)  #    Comments [4]  | 
Sunday, 24 September 2006

Hi

A colleague of mine, Morten la Cour Thomsen, who is "MCTS: BizTalk Server 2004" AND "MCTS: BizTalk Server 2006" discovered something strange the other day. In fact, it is so strange, that I thought I'd share it here on my blog.

Morten was on a project, where he had taken over another persons BizTalk solution. Unfortunately for Morten, the other guy had decided to put all artefacts into one single assembly. That's right - all schemas, all maps, pipelines, orchestrations.. the works! Just one big assembly.

This turned out to be quite a problem for the company that had this solution, since versioning any single artefact meant versioning the whole thing. That is also why they until now didn't version anything. Should something need to be changed in the big assembly, four steps were performed:

  1. Stop all receive locations
  2. Make the change in the artefact that needed changing
  3. Wait until all long running transactions have stopped
  4. Deploy the new assembly on top of the old one, leaving all versionnumbers the same

Mortens job was to create a better architecture, since it really wasn't ok with the customer to have to stop receiving new messages until all orchestrations had stopped.

One of the steps Morten came across was that he actually at some point needed to call an orchestration that was inside this big assembly. The orchestration that Morten needed to call was being called from other orchestrations inside the assembly, so it was ready to be called (no activate receive shape, etc.). The only problem for Morten was, that the orchestration, off course, was internal to the assembly. Morten could reference the assembly, but he couldn't call the orchestration from within an "Call Orchestration"-shape.

But that's when Morten tried something that I would never have thought of trying: He had the source code for the big assembly. And he had the keyfile that had been used to sign it. So he changed the orchestration to be public, recompiled the big assembly, referenced the newly compiled assembly, added the former internal orchestration to his "Call Orchestration"-shape and compiled his own assembly.

He now deployed his own assembly, but left the old big assembly in place.

Now he had the old big assembly, which still had the internal orchestration inside it. And he had another deployed assembly, which was compiled against the source code with a public orchestration. The big assembly was never redeployed!

But it worked! Mortens orchestration is now calling the internal orchestration of the other assembly, simply because it was compiled against a public orchestration and the signature of the deployed big assembly matches the signature of his newly compiled big assembly.

Very weird, indeed. And it probably isn't meant to do that...

I have a sample solution for BizTalk 2004 you can look at right here: InternalOrchestration.zip (132 KB)

And two sample projects for BizTalk 2006 right here: Calling Internal Orchestration.zip (146,46 KB)

In both cases, the code reflects the internal orchestration AFTER it has been set to public. What you want to do is to

  1. Set the type to "internal" on the called internal orchestration.
  2. Build and deploy the assembly with the internal orchestration.
  3. Test it to see that it works.
  4. Try to build the other assembly. It will fail because of the internal orchestration.
  5. Set the type to "public" on the called orchestration.
  6. Build and deploy the second assembly WITHOUT redeploying the first assembly.
  7. Test it to make sure it works.

So, basically, now you have a way of calling an internal orchestration, as long as you have the source code for it and the key to sign it.

Hope this is useful for someone.

--

eliasen

Sunday, 24 September 2006 23:07:52 (Romance Daylight Time, UTC+02:00)  #    Comments [2]  | 
Saturday, 16 September 2006

Hi

A guy (I think it is a guy, anyways :-) ) on the microsoft.public.biztalk.orchestration newsgroup has a problem with this issue. And since I had the issue myself a long time ago, and always wanted to write a quick blog entry about it, this seemed like a perfect time for it :-)

A quick note: This issue appears on both BizTalk 2004 and BizTalk 2006.

So basically, the problem is: When compiling a BizTalk project, you get the "'projectname.orchestrationname': cannot resolve imported 'service'" error. This occurs when you are compiling a project that has an orchestration inside it, that calls another orchestration in another project that again calls an orchestration in a third project. Confused? I bet! I will give you details, screenshots and explanations in just a few lines.

The quick answer is: The project you are trying to compile must reference the third project.

BUT, to the long answer:

I have created a solution with three projects:

  • ProjectA with ABCSchema.xsd and OrchestrationA.odx
    • Orchestration A does this
      • Receive a message of type ABCSchema.xsd
      • Initialize a string variable to receive the value from a distinguished field in ABCSchema
      • Write the value to the eventlog
      • Call OrchestrationB
  • ProjectB with OrchestrationB.odx
    • Orchestration B does this:
      • Receive the string parameter from OrchestrationA
      • Write the value to the eventlog
      • Call OrchestrationC
  • ProjectC with OrchestrationC.odx
    • Orchestration C does this:
      • Receive the string parameter from OrchestrationB
      • Write the value to the eventlog

Screenshots:

The (very small) schema:

OrchestrationA:

OrchestrationB:

OrchestrationC:

No hokus pokus at all!

In order to call OrchestrationC from OrchestrationB, I added a reference to ProjectC from ProjectB. Both ProjectB and ProjectC compile just fine.

In order to call OrchestrationB from OrchestrationA, I add a reference to ProjectB from ProjectA, but ProjectA wont compile. I get this error:

The famous "cannot resolve imported 'service'" error.

BUT, referencing ProjectC from ProjectA solves this issue, and I can compile just fine.

Actually, the error description indicates it. When compiling ProjectA, it can't import the "ProjectC.OrchestrationC" service. But often, you are maybe compiling the entire solution, and you just see that the file in quesion is projectb.dll. But the error just states that ProjectA cannot import ProjectC.OrchestrationC, which it needs to according to projectb.dll.

Should anyone think that it is really silly that ProjectA needs to reference a dll that another dll references and that this breaks all nice architectures, I would agree. If someone gives me a set of 20 dll's that make up a nice solution he/she has made, and I need to call an orchestration in one of them, then I also need to reference all the dll's that this one dll references, assuming there are internal "Call Orchestration"s between these dll's. I will need to know how these dll's reference eachother in order to reference one of them. Really silly, indeed.

I don't know why they have made it like this, but they have.

I hope this post helps others.

Should you have comments, please don't hesitate... My three projects can be found here: A_calls_B_calls_C.zip (137,08 KB)

--

eliasen

Saturday, 16 September 2006 14:00:22 (Romance Daylight Time, UTC+02:00)  #    Comments [4]  | 
Thursday, 07 September 2006

Hi

Today, I had the pleasure of helping a fellow BizTalk guy on the microsoft.public.biztalk.general newsgroup. He has a schema which showed up with lots of root elements in the schema editor. He wanted to fix that, but how?

The "problem" is well known if you for instance use schemas created by InfoPath 2003. They will look something like this:

There are lots of elements that appear to be the root node. Now, I know that "myFields" is the actual root node that I want to use, but it sure isn't easy to see. What I want shown is this:

And if I create an instance of this schema, I will get this:

<ns0:CustomerName xmlns:ns0="http://schemas.microsoft.com/office/infopath/2003/myXSD/2006-09-07T18:24:45">CustomerName_0</ns0:CustomerName>

But that isn't what I wanted. I wanted this:

<ns0:myFields ns1:anyAttr="anyAttrContents" xmlns:ns1="http://www.w3.org/XML/1998/namespace" xmlns:ns0="http://schemas.microsoft.com/office/infopath/2003/myXSD/2006-09-07T18:24:45">
  <ns0:CustomerName>CustomerName_0</ns0:CustomerName>
  <ns0:OrderLines>
    <ns0:OrderLine ns0:ID="ID">
      <ns0:Description>Description_0</ns0:Description>
      <ns0:Quantity>100</ns0:Quantity>
      <ns0:ItemID>100</ns0:ItemID>
    </ns0:OrderLine>
    <ns0:OrderLine ns0:ID="ID">
      <ns0:Description>Description_0</ns0:Description>
      <ns0:Quantity>100</ns0:Quantity>
      <ns0:ItemID>100</ns0:ItemID>
    </ns0:OrderLine>
    <ns0:OrderLine ns0:ID="ID">
      <ns0:Description>Description_0</ns0:Description>
      <ns0:Quantity>100</ns0:Quantity>
      <ns0:ItemID>100</ns0:ItemID>
    </ns0:OrderLine>
  </ns0:OrderLines>
</ns0:myFields>

So, how do I achive this?

Well, the answer is quite simple, really... although it does involve manually editing the schema file (the .xsd file).

What you want to do is add a BizTalk specific annotation to the schema to let BizTalk Schema Editor know which node is to be treated as the root node.

So my schema looked like this:

<xsd:schema xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2006-09-07T18:24:45" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" targetNamespace="http://schemas.microsoft.com/office/infopath/2003/myXSD/2006-09-07T18:24:45" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:attribute name="ID" type="my:requiredString" />
  <xsd:element name="myFields">
... and a whole bunch more

and I edited it and now it looks like this:

<xsd:schema xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2006-09-07T18:24:45" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" targetNamespace="http://schemas.microsoft.com/office/infopath/2003/myXSD/2006-09-07T18:24:45" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:annotation>
    <xsd:appinfo>
      <b:schemaInfo is_envelope="no" version="1.0" root_reference="myFields" displayroot_reference="myFields" xmlns:b="http://schemas.microsoft.com/BizTalk/2003">
      </b:schemaInfo>
    </xsd:appinfo>
  </xsd:annotation>
  <xsd:attribute name="ID" type="my:requiredString" />
  <xsd:element name="myFields">


So under annotations under appinfo, I added a BizTalk specific schemaInfo element, which describes which node to treat as the root node.

Clever and simple. But remember that you need to do this editing every time a new version of the schema needs to be used.

You can find my schemas here:

myschema.zip (,78 KB)

and here:

correctedmyschema.zip (,88 KB)

 

I hope this helps someone.

--

eliasen

Thursday, 07 September 2006 23:17:51 (Romance Daylight Time, UTC+02:00)  #    Comments [2]  | 

Theme design by Jelle Druyts