BizTalk

Updating multiple nodes with different parents and hierarchical levels using the BizTalk BRE

Oops, this must be the longest and worst blog post title you have ever seen. Let's quickly make clear what I mean:

Recently I needed to update multiple elements using a single rule in the Business Rule Engine (BRE). To most BizTalkers this is nothing special. The thing that complicated this particular scenario was that the elements to update where in different hierarchical levels within the xml instance and thus had different parent nodes.

See the following XML and corresponding XSD instance for an example of this scenario:

<ns0:Customer xmlns:ns0="http://Samples.BRE.Customer">
      <Name>John</Name>
      <Discount>10</Discount>
      <Accounts>
            <Account>
                  <ID>12</ID>
                  <Discount>10</Discount>
            </Account>
            <SubAccounts>
                  <SubAccount>
                        <ID>34</ID>
                        <Discount>10</Discount>
                  </SubAccount>
                  <SubAccount>
                        <ID>56</ID>
                        <Discount>20</Discount>
                  </SubAccount>
                  <SubAccount>
                        <ID>78</ID>
                        <Discount>10</Discount>
                  </SubAccount>
            </SubAccounts>
      </Accounts>
</ns0:Customer>
 
<?xml version="1.0"encoding="utf-16"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns="http://Samples.BRE.Customer"
targetNamespace="http://Samples.BRE.Customer" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:element name="Customer">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="1" maxOccurs="1" name="Name" type="xs:string" />
        <xs:element minOccurs="1" maxOccurs="1" name="Discount" type="xs:string" />
        <xs:element minOccurs="0" maxOccurs="1" name="Accounts">
          <xs:complexType>
            <xs:sequence>
              <xs:element minOccurs="1" maxOccurs="1" name="Account"
 type="_Account" />
              <xs:element minOccurs="0" maxOccurs="1" name="SubAccounts">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element minOccurs="1" maxOccurs="unbounded"
 name="SubAccount" type="_Account" />
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
 </xs:element>
 <xs:complexType name="_Account">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="ID" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="Discount" type="xs:string" />
    </xs:sequence>
 </xs:complexType>
</xs:schema>
 

As you can see, the Discount node in this instance is on a different level in the XML structure. Also it has a different parent  (in this case Customer, Account and SubAccount). Now let’s say we need a rule that updates ALL the Discount nodes that have a value of 10. Of course this could be done easily using three separate rules but that would be a bad solution and could be done more simply.
When we drag and drop a new rule in the BRE based on the above schema. The condition of the rule looks something like this:

the corresponding action would be:

The problem is that, as the xpath statement indicates, this will only affect the Discount nodes directly under the root node. How do we adjust the role so that it will apply to all the Discount nodes in the XML instance?

The solution is to change the XPath Selector and XPath Field properties of the schema. After that we rewrite the rule based on the adjusted values of those properties.

The XPath selector:

The value is by default set to:

/*[local-name()='Customer' and namespace-uri()='http://Samples.BRE.Customer']

We change this to:

//*[local-name()='Discount' and namespace-uri()='']

This will select all the Discount nodes on any level regardless of their parent.

Next we have to think of what to fill in for the Xpath Field property. The Xpath Selector now has the complete xpath statement to get to the desired node set. together the XPath Selector and XPath Field are used by the BRE to reference nodes, so ideally would like to leave the Xpath field empty and remove the default value '*[local-name()='Discount' and namespace-uri()='']' but cannot because the BRE composer won't allow an empty Xpath Field property. This means we need a statement that’s not empty and doesn't affect the nodes selected by the XPath Selector. The 'self::node()' expression will solve this.

The figure below shows the modified values in the Business Rules Composer:

 

After setting these properties, (re)drag the Discount element to the Conditions and Actions sections. The rule looks like this:

Testing the rule in the Business Rule Composer shows that this in fact works:

XML instance before BRE: 

<ns0:Customer xmlns:ns0="http://Samples.BRE.Customer">
      <Name>John</Name>
      <Discount>10</Discount>
      <Accounts>
            <Account>
                  <ID>12</ID>
                  <Discount>10</Discount>
            </Account>
            <SubAccounts>
                  <SubAccount>
                        <ID>34</ID>
                        <Discount>10</Discount>
                  </SubAccount>
                  <SubAccount>
                        <ID>56</ID>
                        <Discount>20</Discount>
                  </SubAccount>
                  <SubAccount>
                        <ID>78</ID>
                        <Discount>10</Discount>
                  </SubAccount>
            </SubAccounts>
      </Accounts>
</ns0:Customer>
 
XML instance after BRE:
 
<ns0:Customer xmlns:ns0="http://Samples.BRE.Customer">
      <Name>John</Name>
      <Discount>40</Discount>
      <Accounts>
            <Account>
                  <ID>12</ID>
                  <Discount>40</Discount>
            </Account>
            <SubAccounts>
                  <SubAccount>
                        <ID>34</ID>
                        <Discount>40</Discount>
                  </SubAccount>
                  <SubAccount>
                        <ID>56</ID>
                        <Discount>20</Discount>
                  </SubAccount>
                  <SubAccount>
                        <ID>78</ID>
                        <Discount>40</Discount>
                  </SubAccount>
            </SubAccounts>
      </Accounts>
</ns0:Customer>

Published: 02-10-2007 by Randal van Splunteren | 0 Comments | 0 Links to this post
 

Developer vs. BizTalk 2 - 1

Ok, so developing solutions in BizTalk is like building a dinosaur from Lego. You start out with the smallest blocks and try to make something big: lots of work. In the office work is in progress on the Aviva MOSS 2007 Portal and Blog sites. Most of the work is pushing pixels around in CSS files. My BizTalk 2006 project is very similar, drawing lines on maps. Very tedious, but someone has to do it. Just make sure it’s not me next time.

Most of the work for BizTalk is very straightforward, once you get the hang of it. That is 1 - 0 for the developer.  Then there is the dreaded “Failed to update binding information”, a.k.a. deployment errors, big time. Somehow, after redeploying several times, BizTalk chokes and gives up on redeployment. Restarting the computer is the only solution and after that there is another half day of productive work, before running into the same problem again. However, today things got worse. I added a pipeline to a project to support the “Flat File Assembler” pipeline component. Presto! No redeployment for me anymore. BizTalk was ready for the pounce: 1 – 1.

There was still a way to get around redeployment, remove the old application and rebuild all bindings. That’s when you appreciate the “Export bindings” option of BizTalk. When I started my project I put all of the stuff in a single project and a single BizTalk application. My mentor Randal quickly pointed out that it is a better idea to split up parts of the solution into smaller projects from the start. At first I still kept all projects in the same application. To tackle the deployment problem a logical thought was to put everything in different applications. Once I got the hang of passing all references to different applications, everything was up and running again.

At the first redeployment it started all over again: “Failed to update binding information”. Now things were worse. Visual Studio even produces more warnings, because it wants to warn you for all cross references. This, on top of all mapping warnings is annoying. Redeployment turned into reference spaghetti, but that is when I pounced. I checked the “Resources” sections of all applications, and removed the latest added pipeline: 2 – 1.

To conclude and summarize, my best guesses to tackle redeployment problems:

  • Delay your first deployment until the last moment. Try testing your schemas and mappings in the development environment while you can.
  • Version all parts of all projects in your solution. Put the versioning also in the namespaces.
  • Make sure that all target namespaces are unique. Duplicates are introduced when you copy and rename a schema and forget the target namespace rename.
  • Check all application’s “Resources” sections. It is all too easy to have an assembly from your project to end up in the common “BizTalk Application 1” application, instead of a preset Application.
  • BizTalk doesn't seem to like more than one level of referencing between applications. At least when you look at deployment issues.
  • An empty pipeline with a Flat File Assembler immediately gives you deployment problems. I will investigate this...

Hope this helps!


Published: 15-02-2007 by Wim The | 0 Comments | 0 Links to this post
 

BizTalk welcomes careful drivers

Making connections to back-office and front-office servers and services has always been part of my job as a software architect of several administrative web applications. Writing a .NET service and agreeing on some FTP, mail or other transport goes a long way, but there is an end to it all: BizTalk. The moment I got the chance to start using BizTalk as part of a company moving to Microsoft Dynamics Crm and planning a major overhaul of existing interconnects I jumped in.

First it was agreed that I would find training in BizTalk 2006, however, it turned out to be impossible enroll on short notice without having to travel too far. As a professional there is no better challenge than diving in and try to make the best of it in the good company of a 500+ page book. Unfortunately, at the moment there happens to be no such book. On the other side I have an experienced and trained BizTalk Aviva colleague, Randal. He takes the lead decisions and is my sparring partner on the job. Last week he mentioned that at this point I would probably learn nothing from any current BizTalk 2006 training, so now I can call myself a BizTalk 2006 literate.

This doesn’t mean that I am completely in tune and this will be a place to share my happy and unhappy BizTalk 2006 moments with you.


Published: 15-02-2007 by Wim The | 0 Comments | 0 Links to this post