PowerShell provider supports BRE deployments

5 March 2010

Just a quick link to a post on Maxime’s blog:

http://maxime-labelle.spaces.live.com/Blog/cns!D8D9369449D177DA!236.entry

Maxime added support for deploying vocabularies and policies to the PowerShell provider for BizTalk. In our opinion this is the easiest way to deploy BRE artefacts.

For now it is only available when you grab and build the latest sources. It will be included in the final 1.0 release of course.

Great work Maxime!


More on untyped messages and Business Rules Engine

4 March 2010

I a previous post I described a way to deal with untyped messages in the Business Rule Engine. This allows for flexibility in scenarios where you want to use a single set of rules (lets call it an “untyped policy”) on multiple types of messages.

Untyped policies work great when tested directly in the Business Rules Composer interface or when executed from .Net code. Unfortunately I stumbled across a nice issue when I wanted to call the rules from an orchestration using the call rules shape.

In my first design of the orchestration I received a message of type System.Xml.XmlDocument. After that I used a call rules shape to execute the policy. Because this is an untyped policy it will only accept a message of System.Xml.XmlDocument as input.

 image

image

Easy! Well, not exactly. While testing this orchestration I did not encounter an exception but found out my rule also did not fire. I enabled rule tracking and saw that my message was not asserted as a fact into the BRE. The tracked information was ‘fact not recognized’.

I tried some things to fix this without success. I ended up viewing the generated C# code for the orchestration and noticed a difference in the code generated for the call rules shape when using untyped and typed policies. For typed policies a new instance of Microsoft.RuleEngine.TypedXmlDocument is created  as a fact wrapper around the orchestration message. This TypedXmlDocument is then passed on to the BRE. For untyped policies this is different. There is no TypedXmlDocument created and the XmlDocument message is passed directly on to the BRE.

So in pseudo C# code, for a typed policy:

typedXDoc = new Microsoft.RuleEngine.TypedXmlDocument("MessageType”, (System.Xml.XmlDocument)orchestrationMessage);
policy.Execute(typedXDoc);

for an untyped policy the code looks like this:

policy.Execute((System.Xml.XmlDocument)orchestrationMessage);

The obvious difference between the two is that the first uses a ‘TypedXmlDocument’ instance to wrap the message. I expected the XLANG code generator to do the same for the untyped version but that is not the case. So what does this mean? Does this mean untyped policies are not supported? Or at least not in orchestrations? Is the only option to use code in an expression shape or helper class to execute untyped policies from within an orchestration?

Because I was completely stuck here I decided to ask BRE (and BizTalk) guru Charles Young for help. 

It turned out that I had to use the special ‘Any’ schema to solve this. As Charles explained to me there are two ways of working with untyped messages in BizTalk. One is the famous XmlDocument approach, the other one is the (undocumented) ‘Any’ schema.

One of the differences between the XmlDocument and ‘Any’ schema is that the latter is treated as a schema type by BizTalk. This means the XLANG code generator will wrap it inside a TypedXmlDocument for a rules call. This exactly like the way it works for a typed policy.

The only two things I had to do was change were the message type from ‘XmlDocument’ to ‘Any’ and accordingly the policy.

This is a picture of the revised orchestration.

image

image

The changes needed in the policy are described in a rewritten version of the original post. You can find it here.

A demo solution around this can be downloaded from here. It contains two orchestrations. One which uses the XMLDocument approach without the rules getting fired. The other using the Any approch with the rules getting fired. Remember to change to paths in the binding file before deploying.

Full credits for this solution go to Charles Young. Charles thanks for helping me out.


Untyped messages and Business Rules Engine (part 2)

4 March 2010

This is a follow up post to my previous post on this topic. The method described in that post doesn’t seem to work when the policy is called from an orchestration. For more background information see this blogpost.

I this post I will use the exact same sample as in the previous post. These are the schemas used:


<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003"

xmlns="http://UntypedBRE.FirstSchema"
targetNamespace='http://UntypedBRE.FirstSchema'

xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="FirstSchema">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="FirstName" type="xs:string" />
        <xs:element name="LastName" type="xs:string" />
        <xs:element name="IsJohn" type="xs:string" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

 

<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003"
xmlns="http://UntypedBRE.SecondSchema"
targetNamespace='http://UntypedBRE.SecondSchema'
xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="SecondSchema">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="FirstName" type="xs:string" />
        <xs:element name="LastName" type="xs:string" />
        <xs:element name="IsJohn" type="xs:string" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

 


<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003"

xmlns="http://UntypedBRE.ThirdSchema"
targetNamespace='http://UntypedBRE.ThirdSchema'

xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="ThirdSchema">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="FirstName" type="xs:string" />
        <xs:element name="LastName" type="xs:string" />
        <xs:element name="IsJohn" type="xs:string" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

In my sample policy I want to check the ‘FirstName’ element. If the value is equal to ‘John’ I want to fill the ‘IsJohn’ element with value ‘yes’. The policy (and single rule) should work for all the above schemas.

The problem is that mentioned schemas belong to a different namespace and have a different rood node, hence in BizTalk terms have a different message type. Because XML schemas facts in the BRE are by default tightly coupled to a specific schema the consequence is that those facts can only operate on a single type of message.

In order to make this generic you have to do the following:

1. Add one of the schemas to the Facts Explorer in the BRE

image

2. Make the schema general

As you can see the Document Type resembles the type of the schema I added. To make this generic I change this value to ‘Microsoft.XLANGs.BaseTypes.Any’. This will make sure that if I use a fact from this schema in a rule it will not be typed to this schema but will be generic:

image

3. Create the rule

In this step I create the rule. The facts will be filled in later.

image

4. Modify the XML facts

In the rule I need to evaluate the ‘FirstName’ fact and optionally set the ‘IsJohn’ fact. Because I want this to work on all schemas I need to define the facts in a generic way. If I click on the ‘FirstName’ fact I can see the xpath statements that point to this fact in the property pane:

image

The ‘Xpath Field’ and ‘Xpath Selector’ properties are directly referring to ‘FirstSchema’ root node and namespace. I change the values to make them generic also:

image

Note that I’m using ‘self::node()’ here. I described this trick before here.

Now the XML fact is no longer pointing to a specific namespace or root node. It just points to a ‘FirstName’ node somewhere in Xml message.

There are of course other possible values for ‘Xpath selector’ and ‘Xpath Field’ to solve this. It all depends on the schemas. If for example the facts you need all have the same parent node you can make the ‘Xpath selector’ select the parent node and the ‘Xpath Field’ select the ‘FirstName’ element.

I do the same for the fact I want to update in the action of the rule:

image

5. Complete the rule by adding the facts

Finally I can drag the XML facts from the Facts Explorer to my rule to complete the condition and create a new action. Like this:

image

You can see that the both the condition and the action are not referring (anymore) to any specific schema  but instead to any schema that has ‘FirstName’  and ‘IsJohn’  elements.

Testing the rule with instances from two different schemas shows that this works:

image

image

One thing to note about this is that the way I changed the xpath statements for the Xml facts comes with a performance penalty. Using things like ‘//*…….’.  will make the engine go through the whole xml tree which is less efficient then using the original full xpath statement. So if performance is a strict requirement be careful using techniques like these.

Another thing is that I do not check for the existence of the nodes first. The policy will crash when an message is processed that does not contain on of the nodes used in the rule.


BizTalk 2006 R2 version number not updated after applying SP 1

4 March 2010

In the past I have published overview tables of BizTalk version numbers. I used to publish a new table whenever a new version or service pack of BizTalk server was released.

I wanted to do the same after the release of SP1 for BizTalk server 2006 R2. Unfortunately it appears that the version number is not updated after applying the service pack. I double checked with some other people but they faced the same issue.

I already reported this issue to Microsoft and blogged about it for the beta release of the SP but it seems they did not fix it for the final release. It think it is a bad thing as you cannot easily determine which version and sp level is running based on the version number.

Anyway the latest version number table looks like this:

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
BizTalk Server 2006 R2 SP1 3.6.1404.0
BizTalk Server 2009   3.8.368.0

I will report the issue to Microsoft again. Although I double checked with some people I might be wrong here. Please let me know if you see different behavior.

In order to still be able to determine the version number in an easy way I wrote a PowerShell script. I have a post about it here.


Determine BizTalk version using PowerShell

4 March 2010

I wrote a very simple PowerShell script which allows you to easily determine the installed BizTalk version and service pack level.

You cannot just look at the version number anymore because it seems SP1 of BizTalk Server 2006 R2 does not update the version number. This means the version numbers for BizTalk 2006 R2 without and with service pack 1 applied are the same. See also my blog post here.

The script will detect any BizTalk version and service pack from 2004 and later. I have tested it on different environments with different BizTalk versions. Please let me know if it is not working :-(

Below is the source, but you can also download it from here.

# Initialization of helper variables
# BizTalk version numbers
$versionBTS2004 = "3.0.4902.0"
$versionBTS2004SP1 = "3.0.6070.0"
$versionBTS2004SP2 = "3.0.7405.0"
$versionBTS2006 = "3.5.1602.0"
$versionBTS2006R2 = "3.6.1404.0"
$versionBTS2009 = "3.8.368.0"

# BizTalk version description
$descriptionBTS2004 = "BizTalk Server 2004"
$descriptionBTS2004SP1 = "BizTalk Server 2004 with service pack 1"
$descriptionBTS2004SP2 = "BizTalk Server 2004 with service pack 2"
$descriptionBTS2006 = "BizTalk Server 2006"
$descriptionBTS2006R2 = "BizTalk Server 2006 R2"
$descriptionBTS2006R2SP1 = "BizTalk Server 2006 R2 with service pack 1"
$descriptionBTS2009 = "BizTalk Server 2009"

# Registry paths
$bizTalkRegistryPath = "HKLM:\SOFTWARE\Microsoft\BizTalk Server"
$biztalk2006SP1UninstallRegistryPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Microsoft Biztalk Server 2006 R2 Service Pack 1 `[KB 974563`]'

$installedVersion = $null

# Check if BizTalk is installed:
if ((Test-Path $bizTalkRegistryPath) -eq $true)
{

# Set location to BizTalk registry key
Set-Location $bizTalkRegistryPath
$key = Get-ChildItem

# Get version number
$productVersion = $key.GetValue("ProductVersion")

switch ($productVersion)
{

$versionBTS2004 { $installedVersion = $descriptionBTS2004 }
$versionBTS2004SP1 { $installedVersion = $descriptionBTS2004SP1 }
$versionBTS2004SP2 { $installedVersion = $descriptionBTS2004SP2 }
$versionBTS2006 { $installedVersion = $versionBTS2006 }
$versionBTS2006R2
{
if ((Test-Path $biztalk2006SP1UninstallRegistryPath) -eq $false)
{
$installedVersion = $descriptionBTS2006R2
}
else
{
$installedVersion = $descriptionBTS2006R2SP1
}
}
$versionBTS2009 { $installedVersion = $descriptionBTS2009 }
}
}

if ($installedVersion -eq $null)
{
Write-Host "BizTalk Server is not installed on this machine."
Exit
}

Write-Host "BizTalk Server installation found on this machine."
Write-Host "Product version number: $productVersion"
Write-Host "Installed version: $installedVersion"