Checking if BizTalk binding file is up-to date during deployment

Dec 11, 2009

As all of you know the number one time consuming task in BizTalk is deployment. How many times have you worked your way through the steps below (and even more interesting - how much time have you spent on them …)

Not only is this time consuming it’s also drop dead boring and therefore also very prone - small mistakes that takes ages to find and fix.

The good news is however that the steps are quite easy to script. We use a combination of a couple of different open-source MsBuild libraries (like this and this) and have created our own little build framework. There is however the BizTalk Deployment Framework by Scott Colescott and Thomas F. Abraham that looks great and is very similar to what we have (ok, ok, it’s a bit more polished …).

Binding files problem

Keeping the binding files in a source control system is of course a super-important part of the whole build concept. If something goes wrong and you need to roll back, or even rebuild the whole solution, having the right version of the binding file is critical.

A problem is however that if someone has done changes to the configuration via the administration console and missed to export these binding to source control we’ll deploy an old version of the binding when redeploying. This can be a huge problem when for example addresses etc have changed on ports and we redeploy old configurations.

What!? If fixed that configuration issue in production last week and now it back …

So how can we reassure that the binding file is up-to-date when deploying?

One solution is to do and export of the current binding file and compare that to one we’re about to deploy in a “pre-deploy”-step using a custom MsBuild target.

Custom build task

Custom build task in MsBuild are easy, a good explanation of how to write one can be found here. The custom task below does the following.

  1. Require a path to the binding file being deployed.

  2. Require a path to the old deployed binding file to compare against.

  3. Using a regular expression to strip out the time stamp in the files as this is the time the file was exported and that will otherwise differ between the files.

  4. Compare the content of the files and return a boolean saying if they are equal or not.

     public class CompareBindingFiles : Task
     {
         string _bindingFileToInstallPath;
         string _bindingFileDeployedPath;
         bool _value = false; 
    
         [Required]
         public string BindingFileToInstallPath
         {
             get { return _bindingFileToInstallPath; }
             set { _bindingFileToInstallPath = value; }
         } 
    
         [Required]
         public string BindingFileDeployedPath
         {
             get { return _bindingFileDeployedPath; }
             set { _bindingFileDeployedPath = value; }
         } 
    
         [Output]
         public bool Value
         {
             get { return _value; }
             set { _value = value; } 
    
         } 
    
         public override bool Execute()
         {
             _value = GetStrippedXmlContent(_bindingFileDeployedPath).Equals(GetStrippedXmlContent(_bindingFileToInstallPath));
             return true; //successful
         } 
    
         private string GetStrippedXmlContent(string path)
         {
             StreamReader reader = new StreamReader(path);
             string content = reader.ReadToEnd();
             Regex pattern = new Regex("<Timestamp>.*</Timestamp>");
             return pattern.Replace(content, string.Empty);
         } 
    
     }
    

Using the build task in MsBuild

After compiling the task above when have to reference the dll in element like below.

<UsingTask AssemblyFile="My.Shared.MSBuildTasks.dll" TaskName="My.Shared.MSBuildTasks.CompareBindingFiles"/>

We can then do the following in out build script!

<!--
    This target will export the current binding file, save as a temporary biding file and use a custom target to compare the exported file against the one we’re about to deploy.
    A boolean value will be returned as IsValidBindingFile telling us if they are equal of not.
-->
<Target Name="IsValidBindingFile" Condition="$(ApplicationExists)=='True'">
    <Message Text="Comparing binding file to the one deployed"/> 

    <Exec Command='BTSTask ExportBindings /ApplicationName:$(ApplicationName) "/Destination:Temp_$(BindingFile)"'/> 

    <CompareBindingFiles BindingFileToInstallPath="$(BindingFile)"
                         BindingFileDeployedPath="Temp_$(BindingFile)">
        <Output TaskParameter="Value" PropertyName="IsValidBindingFile" />
    </CompareBindingFiles> 

    <Message Text="Binding files is equal: $(IsValidBindingFile)" /> 

</Target>

<!--
    This pre-build step runs only if the application exists from before. If so it will check if the binding file we try to deploy is equal to one deployed. If not this step will break the build.
-->
<Target Name="PreBuild" Condition="$(ApplicationExists)=='True'" DependsOnTargets="ApplicationExists;IsValidBindingFile">
    <!--We'll break the build if the deployed binding files doesn't match the one being deployed-->
    <Error Condition="$(IsValidBindingFile) == 'False'" Text="Binding files is not equal to deployed" /> 

<!--All other pre-build steps goes here-->

</Target>

So we now break the build if the binding file being deployed aren’t up-to-date!

This is far from rocket science but can potentially save you from making some stupid mistakes.