BizTalk Server: Get your bindings sorted!
or, a method for sorting your binding file to simplify comparison.
Introduction
This article describes code and a method which sorts the artefacts in your binding file in alphabetical order, maintaining the XML document structure so it still can be imported into BizTalk.
Problem
If you have been around with BizTalk for only a while, you are aware that the artefacts in the binding file moves around from time to time. Specifically, they are exported in database order. There are descriptions on how to change the clustered indexes in the relevant BizTalk database tables to names columns instead of the id columns; an interesting approach but neither obvious nor straightforward.
The need for maintaining binding files arises almost immediately when you store them under version control and there is more than one developer on a project. Someone adds a port here, a receive location there and perhaps an orchestration. Another changes the send pipeline. Are all these changes included in the bindings and not overwritten by the latest check-in? Another need is when you maintain different bindings for different environments, and thus a new artefact has to be merged from dev binding, to QA binding and finally to production binding.
When the artefacts keep moving around in the file, there aren’t many tools that can keep track of hundreds or thousands of artefacts that are several hundred lines apart.
Solution
One solution is to sort the artefacts before comparing or merging and this article will show you how.
The artefacts have to be sorted within their respective parent or grandparent, so that BizTalk can import the bindings after sorting and merging. That is, first node must be <``ModuleRefCollection``>
and within that node, <``ModuleRef``>
nodes must be sorted according to the Name attribute. And within each <``ModuleRef``>
there is a <``TrackedSchemas``>
with several <``Schema``>
nodes, to be sorted according to the FullName and RootName attributes. And so on and so forth.
Since the binding file is XML, it is natural to run an XSL Transform to do the sorting. Running an XSL Transform is easy to code in Powershell. Everything is then wrapped up in a .cmd script for those of you that don’t live in a Powershell all day.
XSL Transform
Update: There is an updated version of this script, that adds some pretty-printing for us humans. The download link is in the See also section.
Here’s the XSLT script that does the actual sorting (sort-bindingfile.xslt):
01.<?xml version="1.0" encoding="utf-8"?>
02.<xsl:stylesheet
03. version="1.0"
04. xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
05. xmlns:msxsl="urn:schemas-microsoft-com:xslt"
06. exclude-result-prefixes="msxsl"
07.>
08. <xsl:output method="xml" indent="yes"/>
09.
10. <xsl:template match="Services">
11. <Services>
12. <xsl:apply-templates select="Service | @*">
13. <xsl:sort select="@Name" data-type="text" order="ascending" />
14. </xsl:apply-templates>
15. </Services>
16. </xsl:template>
17.
18. <xsl:template match="ModuleRefCollection">
19. <ModuleRefCollection>
20. <xsl:apply-templates select="ModuleRef | @*">
21. <xsl:sort select="@Name" data-type="text" order="ascending" />
22. </xsl:apply-templates>
23. </ModuleRefCollection>
24. </xsl:template>
25.
26. <xsl:template match="TrackedSchemas">
27. <TrackedSchemas>
28. <xsl:apply-templates select="Schema | @*">
29. <xsl:sort select="@FullName" data-type="text" order="ascending" />
30. <xsl:sort select="@RootName" data-type="text" order="ascending" />
31. </xsl:apply-templates>
32. </TrackedSchemas>
33. </xsl:template>
34.
35. <xsl:template match="SendPortCollection">
36. <SendPortCollection>
37. <xsl:apply-templates select="SendPort | @*">
38. <xsl:sort select="@Name" data-type="text" order="ascending" />
39. </xsl:apply-templates>
40. </SendPortCollection>
41. </xsl:template>
42.
43. <xsl:template match="ReceivePortCollection">
44. <ReceivePortCollection>
45. <xsl:apply-templates select="ReceivePort | @*">
46. <xsl:sort select="@Name" data-type="text" order="ascending" />
47. </xsl:apply-templates>
48. </ReceivePortCollection>
49. </xsl:template>
50.
51. <xsl:template match="@* | node()">
52. <xsl:copy>
53. <xsl:apply-templates select="@* | node()" />
54. </xsl:copy>
55. </xsl:template>
56.
57.</xsl:stylesheet>
The XSLT is built around templates, one template for each group that shall be sorted. For example, look at the first template, the one that matches the Services node (lines 10-16):
- It first outputs a Services node, and then applies a template selecting all the Service nodes and their attributes. Application of the template sorts the selected nodes, by selecting their Name attribute, sorting as text in ascending order. Any sub-nodes and attributes are taken care of by the last template that matches any other node or attribute that hasn’t been matched already.
The other templates work the same way, and the template that matches TrackedSchemas nodes (lines 26-33) sorts on two attributes; primary on FullName and secondary on RootName.
Powershell script
There aren’t many lines of C# code needed to do an XSL Transform, and in Powershell even fewer. A core transformation consists of three lines:
1.$xslt = New-Object System.Xml.Xsl.XslCompiledTransform;
2.$xslt.Load($xslFilename);
3.$xslt.Transform($xmlFilename, $outputFilename);
The rest of the Powershell script is just arguments checking and house-keeping. This is the complete Powershell script (DoXslTransform.ps1):
01.function DoXslTransform ([string]$xmlFilename, [string]$xslFilename, [string]$outputFilename)
02.{
03. trap [Exception]
04. {
05. Write-Host $_.Exception;
06. }
07.
08. $xslt = New-Object System.Xml.Xsl.XslCompiledTransform;
09. $xslt.Load($xslFilename);
10. $xslt.Transform($xmlFilename, $outputFilename);
11.}
12.
13.###
14.### Main processing:
15.###
16.if ($args.Length -ne 3)
17.{
18. Write-Output "Syntax: powershell -f DoXslTransform.ps1 sourceXmlFilename xslFilename destinationFilename";
19. Exit 1;
20.}
21.[string]$xmlFilename = $args[0];
22.[string]$xslFilename = $args[1];
23.[string]$outputFilename = $args[2];
24.
25.if (!(Test-Path $xmlFilename))
26.{
27. Write-Output "source file $xmlFilename not found";
28. exit 1;
29.}
30.if (!(Test-Path $xslFilename))
31.{
32. Write-Output "transform file $xslFilename not found";
33. exit 1;
34.}
35.Write-Output "Transforming $xmlFilename with $xslFilename to $outputFilename ...";
36.DoXslTransform $xmlFilename $xslFilename $outputFilename;
37.Write-Output "Done.";
This Powershell script actually performs a generic XSL Transform – it runs any valid XSL Transform file on any valid XML document.
Cmd script
And finally, a .cmd script that simplifies things even further by wrapping the Powershell script and specifying the XSLT for you (sort-bindingfile.cmd):
1.@echo off
2.if "%1"=="" goto syntax
3.if "%2"=="" goto syntax
4.powershell -f .\DoXslTransform.ps1 %1 .\sort-bindingfile.xslt %2
5.goto end
6.:syntax
7.echo Syntax: sort-bindingfile.cmd sourcefile.xml destinationfile.xml
8.:end
Sample Usage
A common scenario looks like this (using version control terminology of TFS):
- You, the developer, have added an orchestration and a port and some schemas to a BizTalk Application. You deploy it to your local development BizTalk environment and configure the test bindings. You test your application and when you are satisfied, you export the bindings to a file named Binding1.xml.
- Meanwhile, your colleague has also added artefacts to the same BizTalk Application but in a different project, but he or she was quicker than you to export and check in the bindings.
To successfully merge your changes without overwriting your colleague’s changes, you get the latest version of the binding file and perform a check out on the file, called MainApplicationBinding.xml.
Then, sort both binding files, but first rename the latest MainApplicationBinding file so you keep the working copy of the bindings sorted:
1.ren MainApplicationBinding.xml MainApplicationBinding-unsorted.xml
2.sort-bindingfile.cmd MainApplicationBinding-unsorted.xml MainApplicationBinding.xml
3.sort-bindingfile.cmd Binding1.xml Binding1-sorted.xml
Now, you can compare and merge your sorted Binding1-sorted.xml, with the diff or merge tool of your choosing, into the MyApplicationBinding.xml file. The only differences you will see will be your changes and your colleague’s, since the rest of the artefacts are in the exact same order.
Conclusion
Sorting the artefacts within a BizTalk binding file is a real time and effort saver. If you wish you can maintain the binding files sorted under version control, and if you dare you can create a check-in trigger that sorts it for you automatically upon check in.
The Powershell script is generic and can run any XSL Transform for you.
Source Code
The code above, with some pretty-print enhancement in the XSLT, is available for download.
See also
Another important place to find an extensive amount of BizTalk related articles is the TechNet Wiki itself. The best entry point is BizTalk Server Resources on the TechNet Wiki.