Create message instance from multiroot XSD using DocumentSpec

19 June 2008

Sometimes you’re in a situation where you need to create a message from scratch. Yossi Dahan wrote an excellent blog post on this topic. As shown by this post there are a number of options to achieve this.

 

 

One option is to use the undocumented BizTalk Document Specification (DocumentSpec) API. Although this way of creating a message has some obvious disadvantages (see also comments to Yossi’s blogpost) it can be the best option in certain specific situations.

On of the things you need to do to create a message instance is to create a new instance of the DocSpec class. The constructor of the DocumentSpec class takes the .Net/BizTalk schema type name and the assembly display name that contains the schema as parameters. The code should look something like this:

 

 

string assemblyDisplayName = “TestSchema, Version=1.0.0.0, Culture=neutral, publicKeyToken=xxxxxxxxxxxxxxxx”;  

string schemaName = “TestSchema.MyTestSchema”

DocumentSpec docSpec = new DocumentSpec(schemaName, assemblyDisplayName);

 

 

This code works fine for single root schemas but you’ll get an error of you try this for a multiroot schema (an xsd that has multiple root nodes):

 

 

 

 

 

So how can I make this code work for multi root schemas? It took me a while to find out but the solution is simple. Just add the name of the root node of the message you want to create preceeded by a ‘+’ sign:

 

string assemblyDisplayName = “TestSchema, Version=1.0.0.0, Culture=neutral, publicKeyToken=xxxxxxxxxxxxxxxx”;  

 

string schemaName = “TestSchema.MyTestSchema+myRootNode1

 

DocumentSpec docSpec = new DocumentSpec(schemaName, assemblyDisplayName);

 

 

This will provide the DocumentSpec class with all the information needed to create a message instance. 


Call Rules Shape, Atomic Transactions and the Orchestration Designer

13 June 2008
One of the nice improvements in BizTalk 2006 R1 (BTS2k6R1) and higher is that you don’t need to use an atomic transaction scope around the “Call Rules” shape. I guess the reason for this is that classes used internally by the Business Rules Engine are now serializable while they were not in previous release.
 
Recently the orchestration designer in Visual Studio almost got me. I wanted to use a “Call Rules” shape en saw to my surprise that the shape was grayed out in the shape context menu. This is menu you get when you right click somewhere in the orchestration designer surface.
What was going on here? Was I wrong? Was it wishful thinking? Did this new feature only exist in my head? Do I still have to use the atomic transaction scope in my orchestrations? Because Visual Studio is always right and I’m always wrong I was about to add the scope to my orchestration.
 
Because I still felt a little bit disappointed I decided to have a quick look in the BTS2k6r1 help file. Nothing special was mentioned in the topic “How to Use the Call Rules Shape” however. Still curious I also looked at the same topic in the BTS2k6r2 help file. To my surprise the topic is updated and contains the following note:  
 
In BizTalk Server 2004, you can insert a Call Rules shape within an orchestration or a Scope shape with Transaction Type set to Atomic. In BizTalk Server 2006, you do not need to have an atomic scope to insert a Call Rules shape. You can drag a Call Rules shape into the Orchestration Design Surface from the Toolbox. However, in BizTalk Server 2006, the Call Rules menu item is disabled in the context menu if you try to insert a Call Rules shape inside an orchestration that does not have an atomic scope. This is a limitation with the BizTalk Server 2006 product.
 
So I was right! You don’t have to use an atomic transaction scope anymore. Apparently there is a bug in the orchestration designer. You can only drag a call rules shape from the toolbox to the orchestration designer surface. The same option can only be used from the context menu if you are inside a scope.
 
I really wonder what the reason for this is? Is it just a bug? And why didn’t they solve this in BTS2k6r2? And also will it be solved in the coming R3.
 
Anyway what point do I want to make here? 
  • Visual Studio is not always right. In rare cases you’re right and Visual Studio is not! :-)
  • You don’t have to use an atomic transaction scope anymore when you want to use the “Call Rules” shape.

My article on WCF and BizTalk online

13 June 2008

Last October I wrote an article for the dutch .Net Magazine. It is about the WCF adapters in BizTalk 2006 R2. Initially the article was planned for the December 2007 issue but the editors decided for some reason to publish it in the March 2008 issue.

Besides a paper version, a digital version is now also made available by Microsoft NL. It can be downloaded from here.

Since .Net Magazine is local the article is only available in dutch.


BizTalk Server version number overview

13 June 2008

Many times companies run a number of BizTalk instances on different servers. For example development, test and production servers. Especially large companies can have a lot of instances and environments running at the same time. For various reasons you’re sometimes unable to determine what exact version you’re looking at. Or you just want to know if a certain service pack is installed.

I have read about people with similar problems in the BizTalk newsgroups. I recently encountered this problem too when I wanted to write a little helper class that determines which BizTalk version was installed. I knew that there is a BizTalk version number stored in the registry. The ‘ProductVersion’ key located in ‘HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\BizTalk Server\3.0′ contains this information. The real problem was however how to match this number to a BizTalk version or Service Pack. After searching the net for a long time I decided to make a list myself. I was lucky that I had been to lazy to clean up my harddisk and delete old Biztalk 2004 vpc’s :-) .

Here is the list: 

Product name Service pack Version number
BizTalk Server 2004 - 3.0.4902.0
BizTalk Server 2004 SP1 3.0.6070.0
BizTalk Server 2004 SP2 3.0.7405.0
BizTalk Server 2006 - 3.5.1602.0
BizTalk Server 2006 R2 - 3.6.1404.0

 

I hope this will save some people a lot of time when they are in the same situation I was. Also there might be better ways that I don’t know (maybe ExplorerOM or WMI) to retrieve version information. Please drop a comment in that case.

There is also a version number stored in the BizTalk SQL Server databases. Most of the BizTalk databases contain a table ‘BizTalkDBVersion’ which contains besides the database version number also the product version number. The strange thing is that this number was not altered by the installation of the service packs (SP1 and SP2) on BizTalk 2004. After the upgrade the table still showed ‘3.0.4902.0′ as the product version number while the registry version number was changed.

I’ll try to keep this list updated when new versions or service packs are released.

There is an updated post on this topic. You can find it here.


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

11 June 2008

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.0encoding=utf-16?>
<xs:schema xmlns:b=http://schemas.microsoft.com/BizTalk/2003xmlns=http://Samples.BRE.Customer
targetNamespace=http://Samples.BRE.Customerxmlns:xs=http://www.w3.org/2001/XMLSchema>
 <xs:element name=Customer>
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs=1maxOccurs=1name=Nametype=xs:string />
        <xs:element minOccurs=1maxOccurs=1name=Discounttype=xs:string />
        <xs:element minOccurs=0maxOccurs=1name=Accounts>
          <xs:complexType>
            <xs:sequence>
              <xs:element minOccurs=1maxOccurs=1name=Account
 type=_Account />
              <xs:element minOccurs=0maxOccurs=1name=SubAccounts>
                <xs:complexType>
                  <xs:sequence>
                    <xs:element minOccurs=1maxOccurs=unbounded
 name=SubAccounttype=_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=1maxOccurs=1name=IDtype=xs:string />
      <xs:element minOccurs=1maxOccurs=1name=Discounttype=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>